triangle_mesh.template.cc
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2021 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
27 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
28 
29 #include <iostream>
30 
31 #include "triangle_mesh.template.h"
32 #include "../generic/map_matrix.h"
33 #include "../generic/multi_domain.h"
34 #include "../generic/projection.h"
35 #include "../generic/face_element_as_geometric_object.h"
36 
37 namespace oomph
38 {
39 
40  //======================================================================
41  /// Build with the help of the scaffold mesh coming
42  /// from the triangle mesh generator Triangle.
43  //======================================================================
44  template<class ELEMENT>
46  const bool &use_attributes)
47  {
48  // Mesh can only be built with 2D Telements.
49  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
50 
51  // Create space for elements
52  unsigned nelem = Tmp_mesh_pt->nelement();
53  Element_pt.resize(nelem);
54 
55  // Create space for nodes
56  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
57 
58  // Create a map storing the node_id of the mesh used to update the
59  // node position in the update_triangulateio function
60  std::map<Node*, unsigned> old_global_number;
61 
62  // Store the TriangulateIO node id
63  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
64  {
65  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
66  old_global_number[old_node_pt] = inod;
67  }
68 
69  // Initialize the old node id vector
70  Oomph_vertex_nodes_id.resize(nnode_scaffold);
71 
72  // Create space for nodes
73  Node_pt.resize(nnode_scaffold, 0);
74 
75  // Set number of boundaries
76  unsigned nbound = Tmp_mesh_pt->nboundary();
77 
78  // Resize the boundary information
79  set_nboundary(nbound);
80  Boundary_element_pt.resize(nbound);
81  Face_index_at_boundary.resize(nbound);
82 
83  //If we have different regions, then resize the region
84  //information
85  if (use_attributes)
86  {
87  Boundary_region_element_pt.resize(nbound);
88  Face_index_region_at_boundary.resize(nbound);
89  }
90 
91  // Loop over elements in scaffold mesh, visit their nodes
92  for (unsigned e = 0; e < nelem; e++)
93  {
94  Element_pt[e] = new ELEMENT;
95  }
96 
97  //Number of nodes per element from the scaffold mesh
98  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
99 
100  // Setup map to check the (pseudo-)global node number
101  // Nodes whose number is zero haven't been copied across
102  // into the mesh yet.
103  std::map<Node*, unsigned> global_number;
104  unsigned global_count = 0;
105 
106  // Map of Element attribute pairs
107  std::map<double, Vector<FiniteElement*> > element_attribute_map;
108 
109  // If we're using attributes
110  if (use_attributes)
111  {
112  // If we're using attributes then we need attribute 0 which will
113  // be associated with region 0
114  element_attribute_map[0].resize(0);
115  }
116 
117  // Loop over elements in scaffold mesh, visit their nodes
118  for (unsigned e = 0; e < nelem; e++)
119  {
120  // Loop over all nodes in element
121  for (unsigned j = 0; j < nnod_el; j++)
122  {
123  // Pointer to node in the scaffold mesh
124  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
125 
126  // Get the (pseudo-)global node number in scaffold mesh
127  // (It's zero [=default] if not visited this one yet)
128  unsigned j_global = global_number[scaffold_node_pt];
129 
130  // Haven't done this one yet
131  if (j_global == 0)
132  {
133  // Find and store the node_id in the old nodes map
134  Oomph_vertex_nodes_id[global_count] =
135  old_global_number[scaffold_node_pt];
136 
137  // Get pointer to set of mesh boundaries that this
138  // scaffold node occupies; NULL if the node is not on any boundary
139  std::set<unsigned>* boundaries_pt;
140  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
141 
142  //Storage for the new node
143  Node* new_node_pt = 0;
144 
145  //Is it on boundaries
146  if (boundaries_pt != 0)
147  {
148  //Create new boundary node
149  new_node_pt=
150  finite_element_pt(e)->construct_boundary_node(j,time_stepper_pt);
151 
152  // Add to boundaries
153  for (std::set<unsigned>::iterator it = boundaries_pt->begin(); it
154  != boundaries_pt->end(); ++it)
155  {
156  add_boundary_node(*it, new_node_pt);
157  }
158  }
159  //Build normal node
160  else
161  {
162  //Create new normal node
163  new_node_pt = finite_element_pt(e)->construct_node(j,time_stepper_pt);
164  }
165 
166  // Give it a number (not necessarily the global node
167  // number in the scaffold mesh -- we just need something
168  // to keep track...)
169  global_count++;
170  global_number[scaffold_node_pt] = global_count;
171 
172  // Copy new node, created using the NEW element's construct_node
173  // function into global storage, using the same global
174  // node number that we've just associated with the
175  // corresponding node in the scaffold mesh
176  Node_pt[global_count - 1] = new_node_pt;
177 
178  // Assign coordinates
179  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
180  {
181  new_node_pt->x(i) = scaffold_node_pt->x(i);
182  }
183  }
184  // This one has already been done: Copy accross
185  else
186  {
187  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
188  }
189  }
190 
191  // If we're using attributes
192  if (use_attributes)
193  {
194  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
195  finite_element_pt(e));
196  }
197  }
198 
199  //Now let's construct lists
200  //Find the number of attributes
201  if (use_attributes)
202  {
203  unsigned n_attribute = element_attribute_map.size();
204 
205  //There are n_attribute different regions
206  this->Region_attribute.resize(n_attribute);
207 
208  //Copy the vectors in the map over to our internal storage
209  unsigned count = 0;
210  for (std::map<double, Vector<FiniteElement*> >::iterator it =
211  element_attribute_map.begin(); it!=element_attribute_map.end(); ++it)
212  {
213  this->Region_attribute[count] = it->first;
214  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
215  it->second;
216  ++count;
217  }
218 
219  }
220 
221  // At this point we've created all the elements and
222  // created their vertex nodes. Now we need to create
223  // the additional (midside and internal) nodes!
224 
225  unsigned boundary_id=0;
226 
227  // Get number of nodes along element edge and dimension of element (2)
228  // from first element
229  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
230  unsigned dim = finite_element_pt(0)->dim();
231 
232  // Storage for the local coordinate of the new node
233  Vector<double> s(dim);
234 
235  // Get number of nodes in the element from first element
236  unsigned n_node = finite_element_pt(0)->nnode();
237 
238  //Storage for each global edge of the mesh
239  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
240  Vector < Vector<Node*> > nodes_on_global_edge(n_global_edge);
241 
242  // Loop over elements
243  for (unsigned e = 0; e < nelem; e++)
244  {
245  //Cache pointers to the elements
246  FiniteElement* const elem_pt = finite_element_pt(e);
247  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
248 
249  //The number of edge nodes is 3*(nnode_1d-1)
250  unsigned n_edge_node = 3 * (n_node_1d - 1);
251 
252  //If there are any more nodes, these are internal and can be
253  //constructed and added directly to the mesh
254  for (unsigned n = n_edge_node; n < n_node; ++n)
255  {
256  // Create new node (it can never be a boundary node)
257  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
258 
259  // What are the node's local coordinates?
260  elem_pt->local_coordinate_of_node(n, s);
261 
262  // Find the coordinates of the new node from the existing
263  // and fully-functional element in the scaffold mesh
264  for (unsigned i = 0; i < dim; i++)
265  {
266  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
267  }
268 
269  //Add the node to the mesh's global look-up scheme
270  Node_pt.push_back(new_node_pt);
271  }
272 
273  //Now loop over the mid-side edge nodes
274  //Start from node number 3
275  unsigned n = 3;
276 
277  // Loop over edges
278  for (unsigned j = 0; j < 3; j++)
279  {
280  //Find the boundary id of the edge
281  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
282 
283  //Find the global edge index
284  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
285 
286  //If the nodes on the edge have not been allocated, construct them
287  if (nodes_on_global_edge[edge_index].size() == 0)
288  {
289  //Loop over the nodes on the edge excluding the ends
290  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
291  {
292  //Storage for the new node
293  Node* new_node_pt = 0;
294 
295  //If the edge is on a boundary, construct a boundary node
296  if (boundary_id > 0)
297  {
298  new_node_pt = elem_pt->construct_boundary_node(n, time_stepper_pt);
299  //Add it to the boundary
300  this->add_boundary_node(boundary_id - 1, new_node_pt);
301  }
302  //Otherwise construct a normal node
303  else
304  {
305  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
306  }
307 
308  // What are the node's local coordinates?
309  elem_pt->local_coordinate_of_node(n, s);
310 
311  // Find the coordinates of the new node from the existing
312  // and fully-functional element in the scaffold mesh
313  for (unsigned i = 0; i < dim; i++)
314  {
315  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
316  }
317 
318  //Add to the global node list
319  Node_pt.push_back(new_node_pt);
320 
321  //Add to the edge index
322  nodes_on_global_edge[edge_index].push_back(new_node_pt);
323  //Increment the node number
324  ++n;
325  }
326  }
327  //Otherwise just set the pointers
328  //using the fact that the next time the edge is visited
329  //the nodes must be arranged in the other order because all
330  //triangles have the same orientation
331  else
332  {
333  //Loop over the nodes on the edge excluding the ends
334  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
335  {
336  //Set the local node from the edge but indexed the other
337  //way around
338  elem_pt->node_pt(n) = nodes_on_global_edge[edge_index][n_node_1d - 3
339  - j2];
340  ++n;
341  }
342  }
343 
344  //Set the elements adjacent to the boundary from the
345  //boundary id information
346  if (boundary_id > 0)
347  {
348  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
349  //Need to put a shift in here because of an inconsistent naming
350  //convention between triangle and face elements
351  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
352 
353  //If using regions set up the boundary information
354  if (use_attributes)
355  {
356  unsigned tmp_region =
357  static_cast<unsigned> (Tmp_mesh_pt->element_attribute(e));
358  //Element adjacent to boundary
359  Boundary_region_element_pt[boundary_id - 1]
360  [tmp_region].push_back(elem_pt);
361  //Need to put a shift in here because of an inconsistent naming
362  //convention between triangle and face elements
363  Face_index_region_at_boundary[boundary_id - 1]
364  [tmp_region].push_back((j + 2) % 3);
365  }
366  }
367 
368  } //end of loop over edges
369  } //end of loop over elements
370 
371 
372  // Lookup scheme has now been setup
373  Lookup_for_elements_next_boundary_is_setup = true;
374 
375  }
376 
377 #ifdef OOMPH_HAS_MPI
378 
379  //======================================================================
380  /// \short Identify the segments from the old mesh (original mesh)
381  /// in the new mesh (this) and assign initial and final boundary
382  /// coordinates for the segments that create the boundary
383  //======================================================================
384  template<class ELEMENT>
387  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
388  {
389  // ------------------------------------------------------------------
390  // First: Get the face elements associated with the current boundary
391  // (nonhalo elements only)
392  // ------------------------------------------------------------------
393  // Temporary storage for face elements
394  Vector<FiniteElement*> face_el_pt;
395 
396  // Temporary storage for number of elements adjacent to the boundary
397  unsigned nele = 0;
398 
399  // Temporary storage for elements adjacent to the boundary that have
400  // a common edge (related with internal boundaries)
401  unsigned n_repeated_ele = 0;
402 
403  const unsigned n_regions = this->nregion();
404 
405  // map to associate the face element to the bulk element, necessary
406  // to attach halo face elements at both sides of each found segment
407  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
408 
409  // Temporary storage for already done nodes
410  Vector<std::pair<Node*, Node*> > done_nodes_pt;
411 
412  // If there is more than one region then only use boundary
413  // coordinates from the bulk side (region 0)
414  if (n_regions > 1)
415  {
416  for (unsigned rr = 0 ; rr < n_regions; rr++)
417  {
418  const unsigned region_id =
419  static_cast<unsigned>(this->Region_attribute[rr]);
420 
421  // Loop over all elements on boundaries in region i_r
422  const unsigned nel_in_region =
423  this->nboundary_element_in_region(b, region_id);
424 
425  unsigned nel_repetead_in_region = 0;
426 
427  // Only bother to do anything else, if there are elements
428  // associated with the boundary and the current region
429  if (nel_in_region > 0)
430  {
431  // Flag that activates when a repeated face element is found,
432  // possibly because we are dealing with an internal boundary
433  bool repeated = false;
434 
435  // Loop over the bulk elements adjacent to boundary b
436  for (unsigned e = 0; e < nel_in_region; e++)
437  {
438  // Get pointer to the bulk element that is adjacent to boundary b
439  FiniteElement* bulk_elem_pt =
440  this->boundary_element_in_region_pt(b, region_id, e);
441 
442 #ifdef OOMPH_HAS_MPI
443  // In a distributed mesh only work with nonhalo elements
444  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
445  {
446  // Increase the number of repeated elements
447  n_repeated_ele++;
448  // Go for the next element
449  continue;
450  }
451 #endif
452 
453  //Find the index of the face of element e along boundary b
454  int face_index =
455  this->face_index_at_boundary_in_region(b,region_id,e);
456 
457  // Before adding the new element we need to be sure that
458  // the edge that this element represent has not been
459  // already added
460  FiniteElement* tmp_ele_pt =
461  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
462 
463  const unsigned n_nodes = tmp_ele_pt->nnode();
464 
465  std::pair<Node*, Node*> tmp_pair =
466  std::make_pair(tmp_ele_pt->node_pt(0),
467  tmp_ele_pt->node_pt(n_nodes - 1));
468 
469  std::pair<Node*, Node*> tmp_pair_inverse =
470  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
471  tmp_ele_pt->node_pt(0));
472 
473  // Search for repeated nodes
474  const unsigned n_done_nodes = done_nodes_pt.size();
475  for (unsigned l = 0; l < n_done_nodes; l++)
476  {
477  if (tmp_pair == done_nodes_pt[l] ||
478  tmp_pair_inverse == done_nodes_pt[l])
479  {
480  nel_repetead_in_region++;
481  repeated = true;
482  break;
483  }
484  }
485 
486  // Create new face element
487  if (!repeated)
488  {
489  // Add the pair of nodes (edge) to the node dones
490  done_nodes_pt.push_back(tmp_pair);
491  // Create the map to know if the element is halo
492  face_el_pt.push_back(tmp_ele_pt);
493  // Add the element to the face elements
494  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
495  }
496  else
497  {
498  // Clean up
499  delete tmp_ele_pt;
500  tmp_ele_pt = 0;
501  }
502 
503  // Re-start
504  repeated = false;
505 
506  } // for (e < nel_in_region)
507 
508  nele += nel_in_region;
509 
510  n_repeated_ele += nel_repetead_in_region;
511 
512  } // if (nel_in_region > 0)
513  } // for (rr < n_regions)
514  } // if (n_regions > 1)
515  //Otherwise it's just the normal boundary functions
516  else
517  {
518  // Loop over all elements on boundaries
519  nele = this->nboundary_element(b);
520 
521  //Only bother to do anything else, if there are elements
522  if (nele > 0)
523  {
524  // Flag that activates when a repeated face element is found,
525  // possibly because we are dealing with an internal boundary
526  bool repeated = false;
527 
528  // Loop over the bulk elements adjacent to boundary b
529  for (unsigned e = 0; e < nele; e++)
530  {
531  // Get pointer to the bulk element that is adjacent to boundary b
532  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
533 
534 #ifdef OOMPH_HAS_MPI
535  // In a distributed mesh only work with nonhalo elements
536  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
537  {
538  // Increase the number of repeated elements
539  n_repeated_ele++;
540  // Go for the next element
541  continue;
542  }
543 #endif
544 
545  //Find the index of the face of element e along boundary b
546  int face_index = this->face_index_at_boundary(b, e);
547 
548  // Before adding the new element we need to be sure that
549  // the edge that this element represents has not been
550  // already added (only applies for internal boundaries)
551  FiniteElement* tmp_ele_pt =
552  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
553 
554  const unsigned n_nodes = tmp_ele_pt->nnode();
555 
556  std::pair<Node*, Node*> tmp_pair =
557  std::make_pair(tmp_ele_pt->node_pt(0),
558  tmp_ele_pt->node_pt(n_nodes - 1));
559 
560  std::pair<Node*, Node*> tmp_pair_inverse =
561  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
562  tmp_ele_pt->node_pt(0));
563 
564  // Search for repeated nodes
565  const unsigned n_done_nodes = done_nodes_pt.size();
566  for (unsigned l = 0; l < n_done_nodes; l++)
567  {
568  if (tmp_pair == done_nodes_pt[l] ||
569  tmp_pair_inverse == done_nodes_pt[l])
570  {
571  // Increase the number of repeated elements
572  n_repeated_ele++;
573  // Mark the element as repeated
574  repeated = true;
575  break;
576  }
577  }
578 
579  // Create new face element
580  if (!repeated)
581  {
582  // Add the pair of nodes (edge) to the node dones
583  done_nodes_pt.push_back(tmp_pair);
584  // Add the element to the face elements
585  face_el_pt.push_back(tmp_ele_pt);
586  // Create the map to know if the element is halo
587  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
588  }
589  else
590  {
591  // Free the repeated bulk element!!
592  delete tmp_ele_pt;
593  tmp_ele_pt = 0;
594  }
595 
596  // Re-start
597  repeated = false;
598 
599  } // for (e < nel)
600  } // if (nel > 0)
601 
602  } // else (n_regions > 1)
603 
604  // Do not consider the repeated elements
605  nele-= n_repeated_ele;
606 
607 #ifdef PARANOID
608  if (nele!=face_el_pt.size())
609  {
610  std::ostringstream error_message;
611  error_message
612  << "The independent counting of face elements ("<<nele<<") for "
613  << "boundary ("<<b<<") is different\n"
614  << "from the real number of face elements in the container ("
615  << face_el_pt.size() <<")\n";
616  throw OomphLibError(error_message.str(),
617  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
618  OOMPH_EXCEPTION_LOCATION);
619  }
620 #endif
621 
622  // Continue even thought there are no elements, the processor needs
623  // to participate in the communications
624 
625  // ----------------------------------------------------------------
626  // Second: Sort the face elements, only consider nonhalo elements
627  // ----------------------------------------------------------------
628 
629  // A flag vector to mark those face elements that are considered as
630  // halo in the current processor
631  std::vector<bool> is_halo_face_element(nele,false);
632 
633  // Count the total number of non halo face elements
634  unsigned nnon_halo_face_elements = 0;
635 
636  // We will have halo face elements if the mesh is distributed
637  for (unsigned ie = 0; ie < nele; ie++)
638  {
639  // Get the face element
640  FiniteElement* face_ele_pt = face_el_pt[ie];
641  // Get the bulk element
642  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
643  // Check if the bulk element is halo
644  if (!tmp_bulk_ele_pt->is_halo())
645  {
646  is_halo_face_element[ie] = false;
647  nnon_halo_face_elements++;
648  }
649  else
650  {
651  // Mark the face element as halo
652  is_halo_face_element[ie] = true;
653  }
654  } // for (ie < nele)
655 
656 #ifdef PARANOID
657  // Get the total number of halo face elements
658  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
659  if (nhalo_face_element > 0)
660  {
661  std::ostringstream error_message;
662  error_message
663  << "There should not be halo face elements since they were not "
664  << "considered when computing the face elements\n\n"
665  << "The number of found halo face elements is: "
666  << nhalo_face_element << "\n\n";
667  throw OomphLibError(error_message.str(),
668  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
669  OOMPH_EXCEPTION_LOCATION);
670  }
671 #endif
672 
673  // The vector of list to store the "segments" that compound the
674  // boundary (segments may appear only in a distributed mesh)
675  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
676 
677  // Number of already sorted face elements (only nonhalo elements for
678  // a distributed mesh)
679  unsigned nsorted_face_elements = 0;
680 
681  // Keep track of who's done (this apply to nonhalo only, remember we
682  // are only working with nonhalo elements)
683  std::map<FiniteElement*, bool> done_el;
684 
685  // Keep track of which element is inverted (in distributed mesh the
686  // elements may be inverted with respect to the segment they belong)
687  std::map<FiniteElement*, bool> is_inverted;
688 
689  // Iterate until all possible segments have been created
690  while(nsorted_face_elements < nnon_halo_face_elements)
691  {
692  // The ordered list of face elements (in a distributed mesh a
693  // collection of contiguous face elements define a segment)
694  std::list<FiniteElement*> sorted_el_pt;
695  sorted_el_pt.clear();
696 
697 #ifdef PARANOID
698  // Select an initial element for the segment
699  bool found_initial_face_element = false;
700 #endif
701 
702  FiniteElement* ele_face_pt = 0;
703 
704  unsigned iface = 0;
705  for (iface = 0; iface < nele; iface++)
706  {
707  if (!is_halo_face_element[iface])
708  {
709  ele_face_pt = face_el_pt[iface];
710  // If not done then take it as initial face element
711  if (!done_el[ele_face_pt])
712  {
713 #ifdef PARANOID
714  found_initial_face_element = true;
715 #endif
716  nsorted_face_elements++;
717  iface++; // The next element number
718  sorted_el_pt.push_back(ele_face_pt);
719  // Mark as done
720  done_el[ele_face_pt] = true;
721  break;
722  }
723  }
724  } // for (iface < nele)
725 
726 #ifdef PARANOID
727  if (!found_initial_face_element)
728  {
729  std::ostringstream error_message;
730  error_message
731  <<"Could not find an initial face element for the current segment\n";
732  throw OomphLibError(error_message.str(),
733  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
734  OOMPH_EXCEPTION_LOCATION);
735  }
736 #endif
737 
738  // Number of nodes
739  const unsigned nnod = ele_face_pt->nnode();
740 
741  // Left and right most nodes (the left and right nodes of the
742  // current face element)
743  Node* left_node_pt = ele_face_pt->node_pt(0);
744  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
745 
746  // Continue iterating if a new face element has been added to the
747  // list
748  bool face_element_added = false;
749 
750  // While a new face element has been added to the set of sorted
751  // face elements then re-iterate
752  do
753  {
754  // Start from the next face element since we have already added
755  // the previous one as the initial face element (any previous
756  // face element had to be added on previous iterations)
757  for (unsigned iiface = iface; iiface < nele; iiface++)
758  {
759  // Re-start flag
760  face_element_added = false;
761 
762  // Get the candidate element
763  ele_face_pt = face_el_pt[iiface];
764 
765  // Check that the candidate element has not been done and is
766  // not a halo element
767  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
768  {
769  // Get the left and right nodes of the current element
770  Node* local_left_node_pt = ele_face_pt->node_pt(0);
771  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
772  // New element fits at the left of segment and is not inverted
773  if (left_node_pt == local_right_node_pt)
774  {
775  left_node_pt = local_left_node_pt;
776  sorted_el_pt.push_front(ele_face_pt);
777  is_inverted[ele_face_pt] = false;
778  face_element_added = true;
779  }
780  // New element fits at the left of segment and is inverted
781  else if (left_node_pt == local_left_node_pt)
782  {
783  left_node_pt = local_right_node_pt;
784  sorted_el_pt.push_front(ele_face_pt);
785  is_inverted[ele_face_pt] = true;
786  face_element_added = true;
787  }
788  // New element fits on the right of segment and is not inverted
789  else if (right_node_pt == local_left_node_pt)
790  {
791  right_node_pt = local_right_node_pt;
792  sorted_el_pt.push_back(ele_face_pt);
793  is_inverted[ele_face_pt] = false;
794  face_element_added = true;
795  }
796  // New element fits on the right of segment and is inverted
797  else if (right_node_pt == local_right_node_pt)
798  {
799  right_node_pt = local_left_node_pt;
800  sorted_el_pt.push_back(ele_face_pt);
801  is_inverted[ele_face_pt] = true;
802  face_element_added = true;
803  }
804 
805  if (face_element_added)
806  {
807  done_el[ele_face_pt] = true;
808  nsorted_face_elements++;
809  break;
810  }
811 
812  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
813  } // for (iiface<nnon_halo_face_element)
814  }while(face_element_added &&
815  (nsorted_face_elements < nnon_halo_face_elements));
816 
817  // Store the created segment in the vector of segments
818  segment_sorted_ele_pt.push_back(sorted_el_pt);
819 
820  } // while(nsorted_face_elements < nnon_halo_face_elements);
821 
822  // The number of segments in this processor
823  const unsigned nsegments = segment_sorted_ele_pt.size();
824 
825  // ------------------------------------------------------------------
826  // Third: We have the face elements sorted (nonhalo only), now
827  // assign boundary coordinates to the nodes in the segments. This is
828  // the LOCAL boundary coordinate which is required if the zeta
829  // values need to be inverted
830  // ------------------------------------------------------------------
831  // Necessary in case boundaries with no geom object associated need
832  // to be inverted the zeta values (It is necessary to compute the
833  // arclength but also to store the nodes in a container (set))
834  // ------------------------------------------------------------------
835 
836  // Vector of sets that stores the nodes of each segment based on a
837  // lexicographically order starting from the bottom left node of
838  // each segment
839  Vector<std::set<Node*> > segment_all_nodes_pt;
840 
841  // The arclength of each segment in the current processor
842  Vector<double> segment_arclength(nsegments);
843 
844  // The number of vertices of each segment
845  Vector<unsigned> nvertices_per_segment(nsegments);
846 
847  // The initial zeta for the segment
848  Vector<double> initial_zeta_segment(nsegments);
849 
850  // The final zeta for the segment
851  Vector<double> final_zeta_segment(nsegments);
852 
853 #ifdef PARANOID
854  if (nnon_halo_face_elements > 0 && nsegments == 0)
855  {
856  std::ostringstream error_message;
857  error_message
858  << "The number of segments is zero, but the number of nonhalo\n"
859  << "elements is: (" << nnon_halo_face_elements << ")\n";
860  throw OomphLibError(error_message.str(),
861  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
862  OOMPH_EXCEPTION_LOCATION);
863  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
864 #endif
865 
866  // Go through all the segments and compute the LOCAL boundary
867  // coordinates
868  for (unsigned is = 0; is < nsegments; is++)
869  {
870 #ifdef PARANOID
871  if (segment_sorted_ele_pt[is].size() == 0)
872  {
873  std::ostringstream error_message;
874  error_message
875  << "The (" << is << ")-th segment has no elements\n";
876  throw OomphLibError(error_message.str(),
877  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
878  OOMPH_EXCEPTION_LOCATION);
879  } // if (segment_sorted_ele_pt[is].size() == 0)
880 #endif
881 
882  // Get access to the first element on the segment
883  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
884 
885  // Number of nodes
886  const unsigned nnod = first_ele_pt->nnode();
887 
888  // Get the first node of the current segment
889  Node *first_node_pt = first_ele_pt->node_pt(0);
890  if (is_inverted[first_ele_pt])
891  {
892  first_node_pt = first_ele_pt->node_pt(nnod-1);
893  }
894 
895  // Get access to the last element on the segment
896  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
897 
898  // Get the last node of the current segment
899  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
900  if (is_inverted[last_ele_pt])
901  {
902  last_node_pt = last_ele_pt->node_pt(0);
903  }
904 
905  // Coordinates of left node
906  double x_left = first_node_pt->x(0);
907  double y_left = first_node_pt->x(1);
908 
909  // Initialise boundary coordinate (local boundary coordinate for
910  // boundaries with more than one segment)
911  Vector<double> zeta(1, 0.0);
912 
913  // If the boundary has an associated GeomObject then it is not
914  // necessary to compute the arclength, only read the values from
915  // the nodes at the edges
916  if (this->boundary_geom_object_pt(b)!=0)
917  {
918  first_node_pt->get_coordinates_on_boundary(b, zeta);
919  initial_zeta_segment[is] = zeta[0];
920  last_node_pt->get_coordinates_on_boundary(b, zeta);
921  final_zeta_segment[is] = zeta[0];
922  }
923 
924  // Lexicographically bottom left node
925  std::set<Node*> local_nodes_pt;
926  local_nodes_pt.insert(first_node_pt);
927 
928  // Now loop over nodes in order
929  for (std::list<FiniteElement*>::iterator it =
930  segment_sorted_ele_pt[is].begin();
931  it != segment_sorted_ele_pt[is].end(); it++)
932  {
933  // Get element
934  FiniteElement* el_pt = *it;
935 
936  // Start node and increment
937  unsigned k_nod = 1;
938  int nod_diff = 1;
939  if (is_inverted[el_pt])
940  {
941  k_nod = nnod - 2;
942  nod_diff = -1;
943  }
944 
945  // Loop over nodes
946  for (unsigned j = 1; j < nnod; j++)
947  {
948  Node* nod_pt = el_pt->node_pt(k_nod);
949  k_nod += nod_diff;
950 
951  // Coordinates of right node
952  double x_right = nod_pt->x(0);
953  double y_right = nod_pt->x(1);
954 
955  // Increment boundary coordinate (the arclength)
956  zeta[0] += sqrt(
957  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
958  * (y_right - y_left));
959 
960  // // When we have a GeomObject associated to the boundary we already
961  // // know the zeta values for the nodes, there is no need to compute
962  // // the arclength
963  // if (this->boundary_geom_object_pt(b)==0)
964  // {
965  // // Set boundary coordinate
966  // nod_pt->set_coordinates_on_boundary(b, zeta);
967  // }
968 
969  // Increment reference coordinate
970  x_left = x_right;
971  y_left = y_right;
972 
973  // Get lexicographically bottom left node but only
974  // use vertex nodes as candidates
975  local_nodes_pt.insert(nod_pt);
976  } // for (j < nnod)
977 
978  } // iterator over the elements in the segment
979 
980  // Store the arclength of the segment
981  segment_arclength[is] = zeta[0];
982 
983  // Store the number of vertices in the segment
984  nvertices_per_segment[is] = local_nodes_pt.size();
985 
986  // Add the nodes for the corresponding segment in the container
987  segment_all_nodes_pt.push_back(local_nodes_pt);
988 
989  } // for (is < nsegments)
990 
991  // Get the number of sets for nodes
992 #ifdef PARANOID
993  if (segment_all_nodes_pt.size() != nsegments)
994  {
995  std::ostringstream error_message;
996  error_message
997  <<"The number of segments ("<<nsegments<<") and the number of "
998  <<"sets of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
999  <<"the\nsegments is different!!!\n\n";
1000  throw OomphLibError(
1001  error_message.str(),
1002  OOMPH_CURRENT_FUNCTION,
1003  OOMPH_EXCEPTION_LOCATION);
1004  }
1005 #endif
1006 
1007  // Store the initial arclength for each segment of boundary in the
1008  // current processor, initalise to zero in case we have a non
1009  // distributed boundary
1010  Vector<double> initial_segment_arclength(nsegments,0.0);
1011 
1012  // Associated the index of the current segment to the segment index
1013  // in the original mesh (input mesh)
1014  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1015 
1016  // Each segment needs to know whether it has to be inverted or not
1017  // Store whether a segment needs to be inverted or not
1018  Vector<unsigned> segment_inverted(nsegments);
1019 
1020  // -----------------------------------------------------------------
1021  // Fourth: Identify the segments with the ones in the original mesh
1022  // (has sense only in the adaptation process)
1023  // -----------------------------------------------------------------
1024 
1025  // Now check if there are segments associated to this boundary
1026  if (nsegments > 0)
1027  {
1028 #ifdef PARANOID
1029  // Double check that the same number of coordinates (nsegments)
1030  // have been established for the boundary
1031  const unsigned nsegments_initial_coordinates =
1032  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1033 
1034  const unsigned nsegments_final_coordinates =
1035  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1036 
1037  if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1038  {
1039  std::stringstream error_message;
1040  error_message
1041  <<"The number of segments that present initial coordinates "
1042  <<nsegments_initial_coordinates<<" is different from "
1043  <<"the\nnumber of segments that present final coordinates "
1044  <<nsegments_final_coordinates<<"\n\n";
1045  throw OomphLibError(
1046  error_message.str(),
1047  OOMPH_CURRENT_FUNCTION,
1048  OOMPH_EXCEPTION_LOCATION);
1049  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1050 
1051  // Also check that the number of segments found in the previous
1052  // mesh is the same as the number of segments found in this mesh
1053  if (nsegments_initial_coordinates != nsegments)
1054  {
1055  std::stringstream error_message;
1056  error_message
1057  <<"Working with boundary ("<< b << ").\n The number of initial and "
1058  <<"final coordinates ("
1059  <<nsegments_initial_coordinates<<") is different from\n"
1060  <<"the number of found segments ("<< nsegments <<").\n\n";
1061  throw OomphLibError(
1062  error_message.str(),
1063  OOMPH_CURRENT_FUNCTION,
1064  OOMPH_EXCEPTION_LOCATION);
1065  } // if (nsegments_initial_coordinates != nsegments)
1066 #endif
1067 
1068  // Create a backup for the data from the original mesh
1069  // Backup for the coordinates
1070  Vector<Vector<double> >original_mesh_segment_initial_coordinate(nsegments);
1071  Vector<Vector<double> >original_mesh_segment_final_coordinate(nsegments);
1072  // Backup for the zeta values
1073  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1074  Vector<double> original_mesh_segment_final_zeta(nsegments);
1075  // Backup for the arclengths
1076  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1077  Vector<double> original_mesh_segment_final_arclength(nsegments);
1078  // Do the backup
1079  for (unsigned is = 0; is < nsegments; is++)
1080  {
1081  original_mesh_segment_initial_coordinate[is].resize(2);
1082  original_mesh_segment_final_coordinate[is].resize(2);
1083  for (unsigned k = 0; k < 2; k++)
1084  {
1085  original_mesh_segment_initial_coordinate[is][k] =
1086  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1087  original_mesh_segment_final_coordinate[is][k] =
1088  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1089  }
1090  // Check if the boudary has an associated GeomObject
1091  if (this->boundary_geom_object_pt(b)!=0)
1092  {
1093  original_mesh_segment_initial_zeta[is] =
1094  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1095  original_mesh_segment_final_zeta[is] =
1096  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1097  }
1098  else
1099  {
1100  original_mesh_segment_initial_arclength[is] =
1101  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1102  original_mesh_segment_final_arclength[is] =
1103  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1104  }
1105  } // for (is < nsegments)
1106 
1107  // Clear all the storage
1108  Boundary_segment_inverted[b].clear();
1109  Boundary_segment_initial_coordinate[b].clear();
1110  Boundary_segment_final_coordinate[b].clear();
1111 
1112  Boundary_segment_initial_zeta[b].clear();
1113  Boundary_segment_final_zeta[b].clear();
1114 
1115  Boundary_segment_initial_arclength[b].clear();
1116  Boundary_segment_final_arclength[b].clear();
1117 
1118  // Identify each segment in the processor with the ones created
1119  // by the original mesh
1120  // -----------------------------------------------------------------
1121  // Keep track of the already identified segments
1122  std::map<unsigned,bool> segment_done;
1123  for (unsigned is = 0; is < nsegments; is++)
1124  {
1125 #ifdef PARANOID
1126  // Flag to know if the segment was identified
1127  bool found_original_segment = false;
1128 #endif
1129 
1130  // Get the initial and final coordinates of the current segment
1131  Vector<double> current_seg_initial_coord(2);
1132  Vector<double> current_seg_final_coord(2);
1133 
1134  // Get access to the initial element on the segment
1135  FiniteElement* current_seg_initial_ele_pt =
1136  segment_sorted_ele_pt[is].front();
1137 
1138  // Number of nodes
1139  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1140 
1141  // Get the first node of the current segment
1142  Node *current_seg_first_node_pt=
1143  current_seg_initial_ele_pt->node_pt(0);
1144  if (is_inverted[current_seg_initial_ele_pt])
1145  {
1146  current_seg_first_node_pt =
1147  current_seg_initial_ele_pt->node_pt(nnod-1);
1148  }
1149 
1150  // Get access to the last element on the segment
1151  FiniteElement* current_seg_last_ele_pt =
1152  segment_sorted_ele_pt[is].back();
1153 
1154  // Get the last node of the current segment
1155  Node *current_seg_last_node_pt =
1156  current_seg_last_ele_pt->node_pt(nnod-1);
1157  if (is_inverted[current_seg_last_ele_pt])
1158  {
1159  current_seg_last_node_pt =
1160  current_seg_last_ele_pt->node_pt(0);
1161  }
1162 
1163  // Get the coordinates for the first and last seg node
1164  for (unsigned i = 0; i < 2; i++)
1165  {
1166  current_seg_initial_coord[i]=current_seg_first_node_pt->x(i);
1167  current_seg_final_coord[i]=current_seg_last_node_pt->x(i);
1168  }
1169 
1170  // We have got the initial and final coordinates of the current
1171  // segment, compare those with the initial and final coordinates
1172  // of the original mesh segments to identify which segments is
1173  // which
1174  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1175  {
1176  if (!segment_done[orig_s])
1177  {
1178  // Get the coordinates to compare
1179  Vector<double> initial_coordinate =
1180  original_mesh_segment_initial_coordinate[orig_s];
1181  Vector<double> final_coordinate =
1182  original_mesh_segment_final_coordinate[orig_s];
1183 
1184  // Compute the distance initial(current)-initial(original)
1185  // coordinates
1186  double dist =
1187  ((current_seg_initial_coord[0] - initial_coordinate[0])*
1188  (current_seg_initial_coord[0] - initial_coordinate[0]))
1189  +
1190  ((current_seg_initial_coord[1] - initial_coordinate[1])*
1191  (current_seg_initial_coord[1] - initial_coordinate[1]));
1192  dist = sqrt(dist);
1193 
1194  // If the initial node is the same, check for the last node
1195  if (dist <
1196  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1197  {
1198  // Compute the distance final(current)-final(original)
1199  // coordinates
1200  dist =
1201  ((current_seg_final_coord[0] - final_coordinate[0])*
1202  (current_seg_final_coord[0] - final_coordinate[0]))
1203  +
1204  ((current_seg_final_coord[1] - final_coordinate[1])*
1205  (current_seg_final_coord[1] - final_coordinate[1]));
1206  dist = sqrt(dist);
1207 
1208  // The final node is the same, we have identified the
1209  // segments
1210  if (dist <
1211  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1212  {
1213  // Store the index that relates the previous index with the
1214  // current one
1215  current_segment_to_original_segment_index[is] = orig_s;
1216 
1217  // In this case the segment is not inverted
1218  Boundary_segment_inverted[b].push_back(0);
1219 
1220  // Copy the initial and final coordinates for each segment
1221  Boundary_segment_initial_coordinate[b].push_back(
1222  initial_coordinate);
1223  Boundary_segment_final_coordinate[b].push_back(
1224  final_coordinate);
1225 
1226  // Check if the boundary has an associated GeomObject
1227  if (this->boundary_geom_object_pt(b)!=0)
1228  {
1229  // Copy the initial zeta value for the segment
1230  Boundary_segment_initial_zeta[b].push_back(
1231  original_mesh_segment_initial_zeta[orig_s]);
1232  Boundary_segment_final_zeta[b].push_back(
1233  original_mesh_segment_final_zeta[orig_s]);
1234  }
1235  else
1236  {
1237  // Copy the initial and final arclength for each
1238  // segment
1239  Boundary_segment_initial_arclength[b].push_back(
1240  original_mesh_segment_initial_arclength[orig_s]);
1241  Boundary_segment_final_arclength[b].push_back(
1242  original_mesh_segment_final_arclength[orig_s]);
1243  }
1244  // Mark the segment as done
1245  segment_done[orig_s] = true;
1246 #ifdef PARANOID
1247  found_original_segment = true;
1248 #endif
1249  break;
1250  } // The final(current) node matched with the
1251  // final(original) node
1252  } // The initial(current) node matched with the
1253  // initial(original) node
1254  else
1255  {
1256  // Check the inverted case Compute the distance
1257  // initial(current)-final(original) coordinates
1258  double dist_inv =
1259  ((current_seg_initial_coord[0] - final_coordinate[0])*
1260  (current_seg_initial_coord[0] - final_coordinate[0]))
1261  +
1262  ((current_seg_initial_coord[1] - final_coordinate[1])*
1263  (current_seg_initial_coord[1] - final_coordinate[1]));
1264  dist_inv = sqrt(dist_inv);
1265 
1266  // If the initial node is the same as the final node of
1267  // the segment, check for the last node
1268  if (dist_inv <
1269  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1270  {
1271  // Compute the distance final(current)-initial(original)
1272  // coordinates
1273  dist_inv =
1274  ((current_seg_final_coord[0] - initial_coordinate[0])*
1275  (current_seg_final_coord[0] - initial_coordinate[0]))
1276  +
1277  ((current_seg_final_coord[1] - initial_coordinate[1])*
1278  (current_seg_final_coord[1] - initial_coordinate[1]));
1279  dist_inv = sqrt(dist_inv);
1280 
1281  // The final node is the same as the initial node, we
1282  // have identified the segments
1283  if (dist_inv <
1284  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1285  {
1286  // Store the index that related the previous index with the
1287  // current one
1288  current_segment_to_original_segment_index[is] = orig_s;
1289 
1290  // In this case the segment is inverted
1291  Boundary_segment_inverted[b].push_back(1);
1292 
1293  // Copy the initial and final coordinates for each segment
1294  Boundary_segment_initial_coordinate[b].push_back(
1295  initial_coordinate);
1296  Boundary_segment_final_coordinate[b].push_back(
1297  final_coordinate);
1298 
1299  // Check that the boudary has an associated GeomObject
1300  if (this->boundary_geom_object_pt(b)!=0)
1301  {
1302  // Copy the initial zeta value for the segments
1303  Boundary_segment_initial_zeta[b].push_back(
1304  original_mesh_segment_initial_zeta[orig_s]);
1305  Boundary_segment_final_zeta[b].push_back(
1306  original_mesh_segment_final_zeta[orig_s]);
1307  }
1308  else
1309  {
1310  // Copy the initial and final arclength for each segment
1311  Boundary_segment_initial_arclength[b].push_back(
1312  original_mesh_segment_initial_arclength[orig_s]);
1313  Boundary_segment_final_arclength[b].push_back(
1314  original_mesh_segment_final_arclength[orig_s]);
1315  }
1316  // Mark the segment as done
1317  segment_done[orig_s] = true;
1318 #ifdef PARANOID
1319  found_original_segment = true;
1320 #endif
1321  break;
1322  } // The final(current) node matched with the
1323  // initial(original) node
1324  } // The initial(current) node matched with the
1325  // final(original) node
1326  } // else (the first(current) node did not matched with the
1327  // first(original) node. Else do the inverted case
1328 
1329  } // (!segment_done[orig_s])
1330 
1331  } // (orig_s < nsegments)
1332 
1333 #ifdef PARANOID
1334  if (!found_original_segment)
1335  {
1336  std::stringstream error_message;
1337  error_message
1338  <<"The ("<<is<<")-th segment on the current segment was not\n"
1339  << "found when trying to identify it with the original mesh's\n"
1340  << "segment coordinates\n";
1341  throw OomphLibError(error_message.str(),
1342  OOMPH_CURRENT_FUNCTION,
1343  OOMPH_EXCEPTION_LOCATION);
1344  } // if (!found_original_segment)
1345 #endif
1346  } // for (is < nsegments)
1347 
1348  } // if (nsegments > 0)
1349 
1350  // -------------------------------------------------------------------
1351  // Fourth: The original mesh is different from the current mesh
1352  // (this). For boundaries with no geom object associated check if it
1353  // is required to reverse the zeta values. In order to reverse the
1354  // zeta values it is required to previously compute the arclength of
1355  // the segments and store the nodes in a container (set). NOTE that
1356  // the setup_boundary_coordinate() method is not called for
1357  // boundaries with NO GeomObject associated, so this is the LAST
1358  // CHANCE to do it
1359  // -------------------------------------------------------------------
1360  // The original mesh is the same as the current mesh (this). The
1361  // setup_boundary_method() will be called only for the boundaries
1362  // with NO GeomObject associated
1363  // -------------------------------------------------------------------
1364  if (this != original_mesh_pt)
1365  {
1366  // Get the boundary arclength
1367 
1368  // Get the initial and final zeta values for the boundary
1369  // (arclength) from the original mesh
1370  Vector<double> first_node_zeta_coordinate =
1371  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1372  Vector<double> last_node_zeta_coordinate =
1373  original_mesh_pt->boundary_final_zeta_coordinate(b);
1374 
1375  // The boundary arclength is the maximum of the initial and final
1376  // zeta coordinate
1377  const double boundary_arclength =
1378  std::max(first_node_zeta_coordinate[0],
1379  last_node_zeta_coordinate[0]);
1380 
1381  for (unsigned is = 0; is < nsegments; is++)
1382  {
1383  // Here check if need to invert the elements and the boundary
1384  // coordinates for the segments in a boundary with no GeomObject
1385  // associated
1386  if (boundary_geom_object_pt(b)==0)
1387  {
1388  // This case only applies for the initial and iterative mesh in
1389  // the adaptation process because the method
1390  // setup_boundary_coordinates() is called by the original mesh
1391  // for boundaries with no GeomObject associated
1392 
1393  // We are goind to check if it is necessary to invert the order
1394  // of the zeta values
1395 
1396  // Get the first and last node of the current segment and their
1397  // zeta values (arclength)
1398 
1399  // There is no need to check for nonhalo elements since the
1400  // container has only nonhalo face elements
1401 
1402  // Get access to the first element on the segment
1403  FiniteElement* first_ele_pt=segment_sorted_ele_pt[is].front();
1404 
1405  // Number of nodes
1406  const unsigned nnod = first_ele_pt->nnode();
1407 
1408  // Get the first node of the current segment
1409  Node *first_node_pt = first_ele_pt->node_pt(0);
1410  if (is_inverted[first_ele_pt])
1411  {
1412  first_node_pt = first_ele_pt->node_pt(nnod-1);
1413  }
1414 
1415  // Get access to the last element on the segment
1416  FiniteElement* last_ele_pt=segment_sorted_ele_pt[is].back();
1417 
1418  // Get the last node of the current segment
1419  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
1420  if (is_inverted[last_ele_pt])
1421  {
1422  last_node_pt = last_ele_pt->node_pt(0);
1423  }
1424 
1425  // Get the zeta coordinates for the first and last node
1426  Vector<double> current_segment_initial_arclen(1);
1427  Vector<double> current_segment_final_arclen(1);
1428  // Is the segment in the current mesh (this) inverted?
1429  if (!Boundary_segment_inverted[b][is]) // Not inverted
1430  {
1431  first_node_pt->
1432  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1433  last_node_pt->
1434  get_coordinates_on_boundary(b, current_segment_final_arclen);
1435  }
1436  else // Inverted
1437  {
1438  first_node_pt->
1439  get_coordinates_on_boundary(b, current_segment_final_arclen);
1440  last_node_pt->
1441  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1442  }
1443 
1444  // Once the zeta values have been obtained check if they are set
1445  // in increasing or decreasing order
1446 
1447  // Flag to state that the values in the segment are in increasing
1448  // order
1449  bool increasing_order = false;
1450 
1451  // If the initial zeta value is smaller than the final zeta
1452  // value then they are in increasing order
1453  if (current_segment_initial_arclen[0] <
1454  current_segment_final_arclen[0])
1455  {
1456  increasing_order = true;
1457  }
1458  // If the initial zeta value is greater than the initial zeta
1459  // value then they are in decreasing order
1460  else if (current_segment_initial_arclen[0] >
1461  current_segment_final_arclen[0])
1462  {
1463  increasing_order = false;
1464  }
1465 #ifdef PARANOID
1466  else
1467  {
1468  std::stringstream error_message;
1469  error_message
1470  << "It was not possible to identify if the zeta values on "
1471  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1472  << "increasing or decreasing order.\n--- New mesh ---\n"
1473  << "Current segment initial arclength: ("
1474  << current_segment_initial_arclen[0]<<")\n"
1475  << "First node coordinates: ("
1476  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n"
1477  << "Current segment final arclength: ("
1478  << current_segment_final_arclen[0]<<")\n"
1479  << "Last node coordinates: ("
1480  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n"
1481  << "Current segment arclength: ("
1482  << segment_arclength[is] <<")\n";
1483  throw OomphLibError(error_message.str(),
1484  OOMPH_CURRENT_FUNCTION,
1485  OOMPH_EXCEPTION_LOCATION);
1486  }
1487 #endif
1488 
1489  // Now get the original initial and final arclengths and check
1490  // if they are in increasing or decreasing order
1491  const unsigned prev_s =
1492  current_segment_to_original_segment_index[is];
1493  const double original_segment_initial_arclength =
1494  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1495  const double original_segment_final_arclength =
1496  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1497 
1498  // Flag to check if the values go in increasing or decreasing
1499  // order in the original mesh segment
1500  bool original_increasing_order = false;
1501 
1502  // Now check if the arclengths on the original mesh go in
1503  // increase or decrease order, this is also used to choose the
1504  // starting value to map the values in the current segment
1505  double starting_arclength = 0.0;
1506  if (original_segment_final_arclength >
1507  original_segment_initial_arclength)
1508  {
1509  // ... in increasing order in the original mesh ...
1510  original_increasing_order = true;
1511  // Select the starting arclength
1512  starting_arclength = original_segment_initial_arclength;
1513  }
1514  else if (original_segment_final_arclength <
1515  original_segment_initial_arclength)
1516  {
1517  // ... in decreasing order in the original mesh ...
1518  original_increasing_order = false;
1519  // Select the starting arclength
1520  starting_arclength = original_segment_final_arclength;
1521  }
1522 #ifdef PARANOID
1523  else
1524  {
1525  std::stringstream error_message;
1526  error_message
1527  << "It was not possible to identify if the zeta values on "
1528  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1529  << "increasing or decreasing order.\n--- Original mesh ---\n"
1530  << "Original segment initial arclength: ("
1531  << original_segment_initial_arclength<<")\n"
1532  << "Original segment final arclength: ("
1533  << original_segment_final_arclength<<")\n";
1534  throw OomphLibError(error_message.str(),
1535  OOMPH_CURRENT_FUNCTION,
1536  OOMPH_EXCEPTION_LOCATION);
1537  }
1538 #endif
1539 
1540  // Now scale the zeta values based considering if the zeta
1541  // values from the current mesh (this) go in the same order as
1542  // in the original mesh
1543  if (increasing_order && original_increasing_order)
1544  {
1545  // Current seg
1546  // |------|
1547  // 0 ---- 1
1548  //
1549  // Is mapped to the new values
1550  // |------|
1551  // a ---- b
1552  // a = original_segment_initial_arclength
1553  // b = original_segment_final_arclength
1554  // s = starting_arclength
1555  // The mapping is given by
1556  // new_z = s + z_old * (b - a)
1557 
1558  // Get the nodes associated to the segment
1559  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1560  // Go through all the nodes in the segment an change their
1561  // zeta values
1562  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1563  it != seg_nodes_pt.end(); it++)
1564  {
1565  // Storing for the zeta value
1566  Vector<double> zeta(1);
1567  // Get each node
1568  Node* nod_pt = (*it);
1569  // Get the zeta value of the current node
1570  nod_pt->get_coordinates_on_boundary(b, zeta);
1571  // ... and re-assign it
1572  const double temp =
1573  starting_arclength + (zeta[0] * segment_arclength[is]);
1574  // The zeta value
1575  zeta[0] = temp / boundary_arclength;
1576  // Correct
1577  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1578  {
1579  zeta[0] = 1.0;
1580  }
1581  else if (std::fabs(zeta[0]) < 1.0e-14)
1582  {
1583  zeta[0] = 0.0;
1584  }
1585 
1586  // Set the new value
1587  nod_pt->set_coordinates_on_boundary(b, zeta);
1588  } // Go through all the nodes
1589  } // if (increasing_order && original_increasing_order)
1590  else if (!increasing_order && original_increasing_order)
1591  {
1592  // Current seg
1593  // |------|
1594  // 1 ---- 0
1595  //
1596  // Is mapped to the new values
1597  // |------|
1598  // a ---- b
1599  // a = original_segment_initial_arclength
1600  // b = original_segment_final_arclength
1601  // s = starting_arclength
1602  // The mapping is given by
1603  // new_z = s + (1.0 - z_old) * (b - a)
1604 
1605  // Get the nodes associated to the segment
1606  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1607  // Go through all the nodes in the segment an change their
1608  // zeta values
1609  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1610  it != seg_nodes_pt.end(); it++)
1611  {
1612  // Storing for the zeta value
1613  Vector<double> zeta(1);
1614  // Get each node
1615  Node* nod_pt = (*it);
1616  // Get the zeta value of the current node
1617  nod_pt->get_coordinates_on_boundary(b, zeta);
1618  // ... and re-assign it
1619  const double temp =
1620  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1621  // The zeta value
1622  zeta[0] = temp / boundary_arclength;
1623  // Correct
1624  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1625  {
1626  zeta[0] = 1.0;
1627  }
1628  else if (std::fabs(zeta[0]) < 1.0e-14)
1629  {
1630  zeta[0] = 0.0;
1631  }
1632  // Set the new value
1633  nod_pt->set_coordinates_on_boundary(b, zeta);
1634  } // Go through all the nodes
1635  } // else if (!increasing_order && original_increasing_order)
1636  else if (increasing_order && !original_increasing_order)
1637  {
1638  // Current seg
1639  // |------|
1640  // 0 ---- 1
1641  //
1642  // Is mapped to the new values
1643  // |------|
1644  // b ---- a
1645  // a = original_segment_initial_arclength
1646  // b = original_segment_final_arclength
1647  // s = starting_arclength
1648  // The mapping is given by
1649  // new_z = s + (1.0 - z_old) * |(b - a)|
1650 
1651  // Get the nodes associated to the segment
1652  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1653  // Go through all the nodes in the segment an change their
1654  // zeta values
1655  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1656  it != seg_nodes_pt.end(); it++)
1657  {
1658  // Storing for the zeta value
1659  Vector<double> zeta(1);
1660  // Get each node
1661  Node* nod_pt = (*it);
1662  // Get the zeta value of the current node
1663  nod_pt->get_coordinates_on_boundary(b, zeta);
1664  // ... and re-assign it
1665  const double temp =
1666  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1667  // The zeta value
1668  zeta[0] = temp / boundary_arclength;
1669  // Correct
1670  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1671  {
1672  zeta[0] = 1.0;
1673  }
1674  else if (std::fabs(zeta[0]) < 1.0e-14)
1675  {
1676  zeta[0] = 0.0;
1677  }
1678  // Set the new value
1679  nod_pt->set_coordinates_on_boundary(b, zeta);
1680  } // Go through all the nodes
1681  } // else if (increasing_order && !original_increasing_order)
1682  else if (!increasing_order && !original_increasing_order)
1683  {
1684  // Current seg
1685  // |------|
1686  // 0 ---- 1
1687  //
1688  // Is mapped to the new values
1689  // |------|
1690  // a ---- b
1691  // a = original_segment_initial_arclength
1692  // b = original_segment_final_arclength
1693  // s = starting_arclength
1694  // The mapping is given by
1695  // new_z = s + z_old * |(b - a)|
1696 
1697  // Get the nodes associated to the segment
1698  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1699  // Go through all the nodes in the segment an change their
1700  // zeta values
1701  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1702  it != seg_nodes_pt.end(); it++)
1703  {
1704  // Storing for the zeta value
1705  Vector<double> zeta(1);
1706  // Get each node
1707  Node* nod_pt = (*it);
1708  // Get the zeta value of the current node
1709  nod_pt->get_coordinates_on_boundary(b, zeta);
1710  // ... and re-assign it
1711  const double temp =
1712  starting_arclength + (zeta[0] * segment_arclength[is]);
1713  // The zeta value
1714  zeta[0] = temp / boundary_arclength;
1715  // Correct
1716  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1717  {
1718  zeta[0] = 1.0;
1719  }
1720  else if (std::fabs(zeta[0]) < 1.0e-14)
1721  {
1722  zeta[0] = 0.0;
1723  }
1724  // Set the new value
1725  nod_pt->set_coordinates_on_boundary(b, zeta);
1726  } // Go through all the nodes
1727  } // else if (!increasing_order && !original_increasing_order)
1728 
1729 #ifdef PARANOID
1730  // Verify that the z values of the first and last node are not
1731  // out of the range [0,1]
1732  for (std::list<FiniteElement*>::iterator it_list =
1733  segment_sorted_ele_pt[is].begin();
1734  it_list != segment_sorted_ele_pt[is].end();
1735  it_list++)
1736  {
1737  // Number of nodes in the segment
1738  const unsigned nnod = (*it_list)->nnode();
1739 
1740  // Get the first node of the current segment
1741  Node *first_node_pt = (*it_list)->node_pt(0);
1742  if(is_inverted[(*it_list)])
1743  {
1744  first_node_pt = (*it_list)->node_pt(nnod-1);
1745  }
1746 
1747  // Get the last node of the current segment
1748  Node *last_node_pt = (*it_list)->node_pt(nnod-1);
1749  if(is_inverted[(*it_list)])
1750  {
1751  last_node_pt = (*it_list)->node_pt(0);
1752  }
1753 
1754  // The z value for the first node
1755  Vector<double> zeta(1);
1756  first_node_pt->get_coordinates_on_boundary(b, zeta);
1757  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1758  {
1759  std::ostringstream error_message;
1760  error_message
1761  <<"The boundary coordinate of the first node on boundary ("
1762  << b << ")\nand segment (" << is << ") is out of the "
1763  << "allowed values [0,1]\n"
1764  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1765  << "The vertex coordinates are: ("
1766  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n";
1767  throw OomphLibError(error_message.str(),
1768  OOMPH_CURRENT_FUNCTION,
1769  OOMPH_EXCEPTION_LOCATION);
1770  }
1771 
1772  // The z value for the last node
1773  last_node_pt->get_coordinates_on_boundary(b, zeta);
1774  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1775  {
1776  std::ostringstream error_message;
1777  error_message
1778  <<"The boundary coordinate of the last node on boundary ("
1779  << b << ")\nand segment (" << is << ") is out of the "
1780  << "allowed values [0,1]\n"
1781  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1782  << "The vertex coordinates are: ("
1783  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n";
1784  throw OomphLibError(error_message.str(),
1785  OOMPH_CURRENT_FUNCTION,
1786  OOMPH_EXCEPTION_LOCATION);
1787  }
1788  }
1789 #endif // #ifdef PARANOID
1790 
1791  } // if (boundary_geom_object_pt(b)==0)
1792 
1793  } // for (is < nsegments)
1794 
1795  } // if (this != original_mesh_pt)
1796 
1797  // ------------------------------------------------------------------
1798  // Copy the corrected (possible reversed) info. to the containers of
1799  // the current mesh
1800  // ------------------------------------------------------------------
1801  // Check if there are segments of b boundary in this processor
1802  if (nsegments > 0)
1803  {
1804  // Copy the initial and final coordinates
1805  Boundary_initial_coordinate[b] =
1806  original_mesh_pt->boundary_initial_coordinate(b);
1807 
1808  Boundary_final_coordinate[b] =
1809  original_mesh_pt->boundary_final_coordinate(b);
1810 
1811  // The initial and final zeta coordinates (In case of a geometric
1812  // object those are the limits of the geom object)
1813  Boundary_initial_zeta_coordinate[b] =
1814  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1815 
1816  Boundary_final_zeta_coordinate[b] =
1817  original_mesh_pt->boundary_final_zeta_coordinate(b);
1818 
1819  } // if (nsegments > 0)
1820 
1821  // Set the flag to indicate that the zeta values have been assigned
1822  // for the current boundary
1823  Assigned_segments_initial_zeta_values[b] = true;
1824 
1825  // Clean all the created face elements
1826  for (unsigned i = 0; i < nele; i++)
1827  {
1828  delete face_el_pt[i];
1829  face_el_pt[i] = 0;
1830  }
1831 
1832  }
1833 
1834  //======================================================================
1835  /// \short Compute the boundary segments connectivity for those
1836  /// boundaries that were splited during the distribution process
1837  /// and also the initial zeta values for each segment (the initial
1838  /// and final boundary nodes coordinates)
1839  //======================================================================
1840  template<class ELEMENT>
1843  const unsigned& b)
1844  {
1845  // ------------------------------------------------------------------
1846  // First: Get the face elements associated with the current boundary
1847  // ------------------------------------------------------------------
1848 
1849  // Get the communicator of the mesh
1850  OomphCommunicator* comm_pt = this->communicator_pt();
1851 
1852  // Get the number of processors
1853  const unsigned nproc = comm_pt->nproc();
1854  // Get the rank of the current processor
1855  const unsigned my_rank = comm_pt->my_rank();
1856 
1857  // Temporary storage for face elements
1858  Vector<FiniteElement*> all_face_ele_pt;
1859 
1860  // Flag to know whether we are working with an internal open curve
1861  // and then re-assign the initial and final zeta coordinates for
1862  // each segment (only used when the mesh is distributed)
1863  bool is_internal_boundary = false;
1864 
1865  // map to associate the face element to the bulk element, necessary
1866  // to attach halo face elements at both sides of each found segment
1867  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
1868 
1869  // Select the boundary face elements, using the criteria of highest
1870  // processor in charge and bottom-left element
1871  select_boundary_face_elements(all_face_ele_pt, b, is_internal_boundary,
1872  face_to_bulk_element_pt);
1873 
1874  // Get the number of face elements
1875  const unsigned n_all_face_ele = all_face_ele_pt.size();
1876 
1877  // ----------------------------------------------------------------
1878  // Second: Sort the face elements, only consider nonhalo elements
1879  // ----------------------------------------------------------------
1880 
1881  // A flag vector to mark those face elements that are considered as
1882  // halo in the current processor
1883  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1884 
1885  // Count the total number of non halo face elements
1886  unsigned nnon_halo_face_elements = 0;
1887 
1888  // Only mark the face elements as halo if the mesh is marked as
1889  // distributed
1890  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1891  {
1892  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1893  // Get the bulk element
1894  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1895  // Check if the bulk element is halo
1896  if (!tmp_bulk_ele_pt->is_halo())
1897  {
1898  // Set the flag for non halo element
1899  is_halo_face_element[ie] = false;
1900  // Increase the non halo elements counter
1901  nnon_halo_face_elements++;
1902  }
1903  else
1904  {
1905  // Mark the face element as halo
1906  is_halo_face_element[ie] = true;
1907  }
1908 
1909  } // for (ie < n_ele)
1910 
1911  // Get the total number of halo face elements
1912  const unsigned nhalo_face_element = n_all_face_ele - nnon_halo_face_elements;
1913 
1914  // The vector of list to store the "segments" that compound the
1915  // boundary (segments may appear only in a distributed mesh)
1916  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
1917 
1918  // Number of already sorted face elements (only nonhalo elements for
1919  // a distributed mesh)
1920  unsigned nsorted_face_elements = 0;
1921 
1922  // Keep track of who's done (this apply to nonhalo only, remember we
1923  // are only working with halo elements)
1924  std::map<FiniteElement*, bool> done_el;
1925 
1926  // Keep track of which element is inverted (in distributed mesh the
1927  // elements may be inverted with respect to the segment they belong)
1928  std::map<FiniteElement*, bool> is_inverted;
1929 
1930  // Iterate until all possible segments have been created
1931  while(nsorted_face_elements < nnon_halo_face_elements)
1932  {
1933  // The ordered list of face elements (in a distributed mesh a
1934  // collection of contiguous face elements define a segment)
1935  std::list<FiniteElement*> sorted_el_pt;
1936  sorted_el_pt.clear();
1937 
1938 #ifdef PARANOID
1939  // Select an initial element for the segment (the first not done
1940  // nonhalo element)
1941  bool found_initial_face_element = false;
1942 #endif
1943 
1944  FiniteElement* ele_face_pt = 0;
1945 
1946  unsigned iface = 0;
1947  for (iface = 0; iface < n_all_face_ele; iface++)
1948  {
1949  if (!is_halo_face_element[iface])
1950  {
1951  ele_face_pt = all_face_ele_pt[iface];
1952  // If not done then take it as initial face element
1953  if (!done_el[ele_face_pt])
1954  {
1955 #ifdef PARANOID
1956  found_initial_face_element = true;
1957 #endif
1958  nsorted_face_elements++;
1959  iface++; // The next element number
1960  sorted_el_pt.push_back(ele_face_pt);
1961  // Mark as done
1962  done_el[ele_face_pt] = true;
1963  break;
1964  }
1965  }
1966  } // for (iface < nele)
1967 
1968 #ifdef PARANOID
1969  if (!found_initial_face_element)
1970  {
1971  std::ostringstream error_message;
1972  error_message
1973  <<"Could not find an initial face element for the current segment\n";
1974  // << "----- Possible memory leak -----\n";
1975  throw OomphLibError(error_message.str(),
1976  OOMPH_CURRENT_FUNCTION,
1977  OOMPH_EXCEPTION_LOCATION);
1978  }
1979 #endif
1980 
1981  // Number of nodes
1982  const unsigned nnod = ele_face_pt->nnode();
1983 
1984  // Left and rightmost nodes (the left and right nodes of the
1985  // current face element)
1986  Node* left_node_pt = ele_face_pt->node_pt(0);
1987  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1988 
1989  // Continue iterating if a new face element has been added to the
1990  // list
1991  bool face_element_added = false;
1992 
1993  // While a new face element has been added to the set of sorted
1994  // face elements then re-iterate
1995  do
1996  {
1997  // Start from the next face element since we have already added
1998  // the previous one as the initial face element (any previous
1999  // face element had to be added on previous iterations)
2000  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
2001  {
2002  // Re-start flag
2003  face_element_added = false;
2004 
2005  // Get the candidate element
2006  ele_face_pt = all_face_ele_pt[iiface];
2007 
2008  // Check that the candidate element has not been done and is
2009  // not a halo element
2010  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2011  {
2012  // Get the left and right nodes of the current element
2013  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2014  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2015 
2016  // New element fits at the left of segment and is not inverted
2017  if (left_node_pt == local_right_node_pt)
2018  {
2019  left_node_pt = local_left_node_pt;
2020  sorted_el_pt.push_front(ele_face_pt);
2021  is_inverted[ele_face_pt] = false;
2022  face_element_added = true;
2023  }
2024  // New element fits at the left of segment and is inverted
2025  else if (left_node_pt == local_left_node_pt)
2026  {
2027  left_node_pt = local_right_node_pt;
2028  sorted_el_pt.push_front(ele_face_pt);
2029  is_inverted[ele_face_pt] = true;
2030  face_element_added = true;
2031  }
2032  // New element fits on the right of segment and is not inverted
2033  else if (right_node_pt == local_left_node_pt)
2034  {
2035  right_node_pt = local_right_node_pt;
2036  sorted_el_pt.push_back(ele_face_pt);
2037  is_inverted[ele_face_pt] = false;
2038  face_element_added = true;
2039  }
2040  // New element fits on the right of segment and is inverted
2041  else if (right_node_pt == local_right_node_pt)
2042  {
2043  right_node_pt = local_left_node_pt;
2044  sorted_el_pt.push_back(ele_face_pt);
2045  is_inverted[ele_face_pt] = true;
2046  face_element_added = true;
2047  }
2048 
2049  if (face_element_added)
2050  {
2051  done_el[ele_face_pt] = true;
2052  nsorted_face_elements++;
2053  break;
2054  }
2055 
2056  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2057  } // for (iiface<nnon_halo_face_element)
2058  }while(face_element_added &&
2059  (nsorted_face_elements < nnon_halo_face_elements));
2060 
2061  // Store the created segment in the vector of segments
2062  segment_sorted_ele_pt.push_back(sorted_el_pt);
2063 
2064  } // while(nsorted_face_elements < nnon_halo_face_elements);
2065 
2066  // -----------------------------------------------------------------
2067  // Third: We have the face elements sorted (in segments), now assign
2068  // boundary coordinates to the nodes in the segments, this is the
2069  // LOCAL boundary coordinate and further communication is needed to
2070  // compute the GLOBAL boundary coordinates
2071  // -----------------------------------------------------------------
2072 
2073  // Vector of sets that stores the nodes of each segment based on a
2074  // lexicographically order starting from the bottom left node of
2075  // each segment
2076  Vector<std::set<Node*> > segment_all_nodes_pt;
2077 
2078  // The number of segments in this processor
2079  const unsigned nsegments = segment_sorted_ele_pt.size();
2080 // DEBP(nsegments);
2081 
2082 #ifdef PARANOID
2083  if (nnon_halo_face_elements > 0 && nsegments == 0)
2084  {
2085  std::ostringstream error_message;
2086  error_message
2087  << "The number of segments is zero, but the number of nonhalo\n"
2088  << "elements is: (" << nnon_halo_face_elements << ")\n";
2089  throw OomphLibError(error_message.str(),
2090  OOMPH_CURRENT_FUNCTION,
2091  OOMPH_EXCEPTION_LOCATION);
2092  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2093 #endif
2094 
2095  // The arclength of each segment in the current processor
2096  Vector<double> segment_arclength(nsegments);
2097 
2098  // The number of vertices of each segment
2099  Vector<unsigned> nvertices_per_segment(nsegments);
2100 
2101  // The initial zeta for the segment
2102  Vector<double> initial_zeta_segment(nsegments);
2103 
2104  // The final zeta for the segment
2105  Vector<double> final_zeta_segment(nsegments);
2106 
2107  // Go through all the segments and compute its ARCLENGTH (if the
2108  // boundary has a GeomObject associated then assign the initial and
2109  // final zeta values for the segment)
2110  for (unsigned is = 0; is < nsegments; is++)
2111  {
2112 #ifdef PARANOID
2113  if (segment_sorted_ele_pt[is].size() == 0)
2114  {
2115  std::ostringstream error_message;
2116  error_message
2117  << "The (" << is << ")-th segment has no elements\n";
2118  throw OomphLibError(error_message.str(),
2119  OOMPH_CURRENT_FUNCTION,
2120  OOMPH_EXCEPTION_LOCATION);
2121  } // if (segment_sorted_ele_pt[is].size() == 0)
2122 #endif
2123 
2124  // Get access to the first element on the segment
2125  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2126 
2127  // Number of nodes
2128  const unsigned nnod = first_ele_pt->nnode();
2129 
2130  // Get the first node of the current segment
2131  Node *first_node_pt = first_ele_pt->node_pt(0);
2132  if (is_inverted[first_ele_pt])
2133  {
2134  first_node_pt = first_ele_pt->node_pt(nnod-1);
2135  }
2136 
2137  // Coordinates of left node
2138  double x_left = first_node_pt->x(0);
2139  double y_left = first_node_pt->x(1);
2140 
2141  // Initialise boundary coordinate (local boundary coordinate for
2142  // boundaries with more than one segment)
2143  Vector<double> zeta(1, 0.0);
2144 
2145  // If we have associated a GeomObject then it is not necessary to
2146  // compute the arclength, only read the values from the nodes at
2147  // the edges and set the initial and final zeta segment values
2148  if (this->boundary_geom_object_pt(b)!=0)
2149  {
2150  // Get the initial node coordinate
2151  first_node_pt->get_coordinates_on_boundary(b, zeta);
2152  // Set the initial zeta segment value
2153  initial_zeta_segment[is] = zeta[0];
2154 
2155  // Get access to the last element on the segment
2156  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2157 
2158  // Get the last node of the current segment
2159  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2160  if (is_inverted[last_ele_pt])
2161  {
2162  last_node_pt = last_ele_pt->node_pt(0);
2163  }
2164 
2165  // Get the final node coordinate
2166  last_node_pt->get_coordinates_on_boundary(b, zeta);
2167  // Set the final zeta segment value
2168  final_zeta_segment[is] = zeta[0];
2169 
2170  }
2171 
2172  // Sort the nodes in the segment (lexicographically bottom left
2173  // node)
2174  std::set<Node*> local_nodes_pt;
2175  // Insert the first node
2176  local_nodes_pt.insert(first_node_pt);
2177 
2178  // Now loop over nodes in order and increase the ARCLENGTH
2179  for (std::list<FiniteElement*>::iterator it =
2180  segment_sorted_ele_pt[is].begin();
2181  it != segment_sorted_ele_pt[is].end(); it++)
2182  {
2183  // Get the pointer to the element
2184  FiniteElement* el_pt = (*it);
2185 
2186  // Start node and increment
2187  unsigned k_nod = 1;
2188  int nod_diff = 1;
2189  // Access nodes in reverse?
2190  if (is_inverted[el_pt])
2191  {
2192  k_nod = nnod - 2;
2193  nod_diff = -1;
2194  }
2195 
2196  // Loop over nodes in the face element
2197  for (unsigned j = 1; j < nnod; j++)
2198  {
2199  Node* nod_pt = el_pt->node_pt(k_nod);
2200  k_nod += nod_diff;
2201 
2202  // Coordinates of right node
2203  double x_right = nod_pt->x(0);
2204  double y_right = nod_pt->x(1);
2205 
2206  // Increment boundary coordinate (the arclength)
2207  zeta[0] += sqrt(
2208  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
2209  * (y_right - y_left));
2210 
2211  // When we have a GeomObject associated to the boundary we already
2212  // know the zeta values for the nodes, there is no need to compute
2213  // the arclength
2214 // if (this->boundary_geom_object_pt(b)==0)
2215 // {
2216 // // Set boundary coordinate
2217 // // nod_pt->set_coordinates_on_boundary(b, zeta);
2218 // }
2219 
2220  // Increment reference coordinate
2221  x_left = x_right;
2222  y_left = y_right;
2223 
2224  // Get lexicographically bottom left node but only
2225  // use vertex nodes as candidates
2226  local_nodes_pt.insert(nod_pt);
2227 
2228  } // for (j < nnod)
2229 
2230  } // iterator over the elements in the segment
2231 
2232  // Info. to be passed to other processors
2233  // The initial arclength for the segment that goes after this depends
2234  // on the current segment arclength
2235  segment_arclength[is] = zeta[0];
2236 
2237  // Info. to be passed to the other processors
2238  // The initial vertex number for the segment that goes after this
2239  // depends on the current segment vertices number
2240  nvertices_per_segment[is] = local_nodes_pt.size();
2241 
2242  // Add the nodes for the corresponding segment in the container
2243  segment_all_nodes_pt.push_back(local_nodes_pt);
2244 
2245  // The attaching of the halo elements at both sides of the segments is
2246  // performed only if segments connectivity needs to be computed
2247 
2248  } // for (is < nsegments)
2249 
2250  // Container to store the number of vertices before each segment,
2251  // initialise to zero in case we have a non distributed boundary
2252  Vector<unsigned> nvertices_before_segment(nsegments,0);
2253 
2254  // Store the initial arclength for each segment of boundary in the
2255  // current processor, initalise to zero in case we have a non
2256  // distributed boundary
2257  Vector<double> initial_segment_arclength(nsegments,0.0);
2258 
2259  // Info. to be passed to other processors
2260  // If the boundary is distributed we need to know which processors does
2261  // have the initial and final segments, this helps to get the first and
2262  // last nodes coordinates (info. used to scale the bound coordinates)
2263 
2264  // Processors with the initial and final segment
2265  unsigned proc_with_initial_seg = 0;
2266  unsigned proc_with_final_seg = 0;
2267 
2268  // ... and the index of those segments (only of interest in the
2269  // processors that have the initial and final segments)
2270  unsigned initial_segment = 0;
2271  unsigned final_segment = 0;
2272 
2273  // Each segment needs to know whether it has to be inverted or not
2274  // Store whether a segment needs to be inverted or not
2275  Vector<unsigned> segment_inverted(nsegments);
2276 
2277  // Before attaching the halo elements create a copy of the data
2278  // structure without halo elements
2279  Vector<std::list<FiniteElement*> > segment_sorted_nonhalo_ele_pt(nsegments);
2280  for (unsigned is = 0; is < nsegments; is++)
2281  {
2282  for (std::list<FiniteElement*>::iterator it_seg =
2283  segment_sorted_ele_pt[is].begin();
2284  it_seg != segment_sorted_ele_pt[is].end();
2285  it_seg++)
2286  {
2287  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2288  }
2289 
2290  } // for (is < nsegments)
2291 
2292  // --------------------------------------------------------------
2293  // Attach the halo elements at both sides of the segments
2294  for (unsigned is = 0; is < nsegments; is++)
2295  {
2296  // Get access to the first element on the segment
2297  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2298 
2299  // Number of nodes
2300  const unsigned nnod = first_ele_pt->nnode();
2301 
2302  // Get the first node of the current segment
2303  Node *first_node_pt = first_ele_pt->node_pt(0);
2304  if (is_inverted[first_ele_pt])
2305  {
2306  first_node_pt = first_ele_pt->node_pt(nnod-1);
2307  }
2308 
2309  // Get access to the last element on the segment
2310  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2311 
2312  // Get the last node of the current segment
2313  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2314  if (is_inverted[last_ele_pt])
2315  {
2316  last_node_pt = last_ele_pt->node_pt(0);
2317  }
2318 
2319  // -----------------------------------------------------------------
2320  // Fourth: Now attach the halo elements to the left and right side
2321  // of each segment
2322  // -----------------------------------------------------------------
2323  bool attached_left_halo = false;
2324  bool attached_right_halo = false;
2325  if (nhalo_face_element > 0)
2326  {
2327  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2328  {
2329  // Get the candidate element
2330  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2331 
2332  // Check that the element is a halo face element, we do not check
2333  // if the element has been already done since the halo elements
2334  // may be connected to more than one segment (2 at most), to the
2335  // left and right of different segments
2336  //
2337  // Segment k Halo Segment r
2338  // |---|---|---| |xxx| |---|---|---|
2339  //
2340  // Segment k Halo Segment r
2341  // |---|---|---|xxx|---|---|---|
2342  //
2343  if (is_halo_face_element[iiface])
2344  {
2345  // Get its left and right nodes
2346  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2347  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod-1);
2348  // The halo element fits to the left of segment
2349  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2350  first_node_pt == left_node_pt))
2351  {
2352  // Add the halo element to the left of the segment
2353  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2354 
2355  // Once a halo face element has been added to the left
2356  // mark as found halo to the left
2357  attached_left_halo = true;
2358  }
2359  // The halo element fits to the right of the segment
2360  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2361  last_node_pt == right_node_pt))
2362  {
2363  // Add the halo element to the right of the segment
2364  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2365  // Once a halo face element has been added to the right
2366  // mark as found halo to the right
2367  attached_right_halo = true;
2368  }
2369  // If we have already found elements to left and right then
2370  // break the loop
2371  if (attached_left_halo && attached_right_halo)
2372  {break;}
2373 
2374  } // if (is_halo_face_element[iiface])
2375 
2376  } // for (iiface < nel)
2377 
2378  } // if (nhalo_face_element > 0)
2379 
2380  } // for (is < nsegments)
2381 
2382  // The segments now have local coordinates assigned and halo
2383  // elements attached to them. Store that info. in the corresponding
2384  // data structures and be ready to send that info. to a root
2385  // processor. The root processor will be in charge of computing the
2386  // boundary coordinates for each segment of the boundary.
2387 
2388  // For each segment store the following information
2389  // --------------------------------------------------------------------
2390  // Stores the "rank" of the processor to the left of each segment,
2391  // zero if there is no processor to the left which states that the
2392  // segment is the first one on the boundary
2393  Vector<unsigned> left_processor_plus_one(nsegments);
2394 
2395  // Stores the "rank" of the processor to the right of each segment,
2396  // zero if there is no processor to the right which states that the
2397  // segment is the last one on the boundary
2398  Vector<unsigned> right_processor_plus_one(nsegments);
2399 
2400  // The id. of the halo element to the left of the segment, note that
2401  // this info. is not necessary if there is no processor to the left
2402  // of the segment
2403  Vector<unsigned> left_halo_element(nsegments);
2404 
2405  // The id. of the halo element to the right of the segment, note that
2406  // this info. is not necessary if there is no processor to the right
2407  // of the segment
2408  Vector<unsigned> right_halo_element(nsegments);
2409 
2410  // The id. of the haloed element to the left of the segment, note that
2411  // this info. is not necessary if there is no processor to the left
2412  // of the segment
2413  Vector<unsigned> left_haloed_element(nsegments);
2414 
2415  // The id. of the haloed element to the right of the segment, note
2416  // that this info. is not necessary if there is no processor to the
2417  // right of the segment
2418  Vector<unsigned> right_haloed_element(nsegments);
2419 
2420  // Go through all the segments and get the info.
2421  for (unsigned is = 0; is < nsegments; is++)
2422  {
2423  // Get access to the left most face element on the segment
2424  FiniteElement* left_face_ele_pt=segment_sorted_ele_pt[is].front();
2425 
2426  // Get the corresponding bulk element and check whether it is a halo
2427  // element or not
2428  FiniteElement* tmp_left_bulk_ele_pt =
2429  face_to_bulk_element_pt[left_face_ele_pt];
2430 
2431  // Check if the bulk element is halo
2432  if (tmp_left_bulk_ele_pt->is_halo())
2433  {
2434  // Then store the corresponding info.
2435  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2436 #ifdef PARANOID
2437  if (left_proc < 0)
2438  {
2439  std::ostringstream error_message;
2440  error_message
2441  << "The current bulk element (left) is marked as halo but "
2442  << "the processor holding\nthe non-halo counterpart is "
2443  << "negative!\n";
2444  throw OomphLibError(error_message.str(),
2445  OOMPH_CURRENT_FUNCTION,
2446  OOMPH_EXCEPTION_LOCATION);
2447  }
2448 #endif
2449  // The processor "rank" to the left
2450  unsigned left_processor = static_cast<unsigned>(left_proc);
2451  left_processor_plus_one[is] = left_processor + 1;
2452 
2453  // Now get the id of the halo element to the left
2454  GeneralisedElement *left_element_pt = tmp_left_bulk_ele_pt;
2455 
2456  // Get the halo elements with left processor
2457  Vector<GeneralisedElement*> left_halo_element_pt =
2458  this->halo_element_pt(left_processor);
2459 
2460 #ifdef PARANOID
2461  // Flag to state that the halo element was found
2462  bool left_halo_element_found = false;
2463 #endif
2464 
2465  const unsigned n_halo_left = left_halo_element_pt.size();
2466  for (unsigned lh = 0; lh < n_halo_left; lh++)
2467  {
2468  if (left_element_pt == left_halo_element_pt[lh])
2469  {
2470  left_halo_element[is] = lh;
2471 #ifdef PARANOID
2472  left_halo_element_found = true;
2473 #endif
2474  break;
2475  }
2476  } // for (lh < n_halo_left)
2477 
2478 #ifdef PARANOID
2479  if (!left_halo_element_found)
2480  {
2481  std::ostringstream error_message;
2482  error_message
2483  << "The current bulk element (left) marked as halo was "
2484  << "not found in the vector of halo\nelements associated "
2485  << "with the (" << left_processor << ") processor.\n\n";
2486  throw OomphLibError(error_message.str(),
2487  OOMPH_CURRENT_FUNCTION,
2488  OOMPH_EXCEPTION_LOCATION);
2489  } // if (!left_halo_element_found)
2490 #endif
2491 
2492  // Get the left-most nonhalo element (use the backup list of
2493  // nonhalo elements)
2494  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2495 
2496  // Get the corresponding bulk element
2497  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2498 
2499 #ifdef PARANOID
2500  // This element should not be marked as halo
2501  if (tmp_left_bulk_ele_pt->is_halo())
2502  {
2503  std::ostringstream error_message;
2504  error_message
2505  << "The bulk element represetation of the left-most nonhalo face\n"
2506  << "element of the current segment ("<<is<<") is marked as halo,\n"
2507  << "but the face element created from it is nonhalo\n";
2508  throw OomphLibError(error_message.str(),
2509  OOMPH_CURRENT_FUNCTION,
2510  OOMPH_EXCEPTION_LOCATION);
2511  } // if (tmp_left_bulk_ele_pt->is_halo())
2512 #endif
2513 
2514  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2515  // to search in the haloed vector
2516  left_element_pt = tmp_left_bulk_ele_pt;
2517 
2518 #ifdef PARANOID
2519  // Flag to state that the haloed element was found
2520  bool left_haloed_element_found = false;
2521 #endif
2522 
2523  // Now get the id for the haloed element to the left, get the
2524  // haloed elements from the processor to the left
2525  Vector<GeneralisedElement*> left_haloed_element_pt =
2526  this->haloed_element_pt(left_processor);
2527 
2528  const unsigned nhaloed_left = left_haloed_element_pt.size();
2529  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2530  {
2531  if (left_element_pt == left_haloed_element_pt[lhd])
2532  {
2533  left_haloed_element[is] = lhd;
2534 #ifdef PARANOID
2535  left_haloed_element_found = true;
2536 #endif
2537  break;
2538  }
2539  } // for (lhd < nhaloed_left)
2540 
2541 #ifdef PARANOID
2542  if (!left_haloed_element_found)
2543  {
2544  std::ostringstream error_message;
2545  error_message
2546  << "The current bulk element (left) marked as haloed was "
2547  << "not found in the vector of haloed\nelements associated "
2548  << "with processor ("<< left_processor << ").\n";
2549  throw OomphLibError(error_message.str(),
2550  OOMPH_CURRENT_FUNCTION,
2551  OOMPH_EXCEPTION_LOCATION);
2552  }
2553 #endif
2554  } // if (tmp_left_bulk_ele_pt->is_halo())
2555  else
2556  {
2557  // If not halo then state the info. to indicate that
2558  left_processor_plus_one[is] = 0;
2559  // Null this info.
2560  left_halo_element[is] = 0;
2561  // Null this info.
2562  left_haloed_element[is] = 0;
2563  }
2564 
2565  // Get access to the right most face element on the segment
2566  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2567 
2568  // Get the corresponding bulk element and check whether it is
2569  // a halo element or not
2570  FiniteElement* tmp_right_bulk_ele_pt =
2571  face_to_bulk_element_pt[right_face_ele_pt];
2572 
2573  // Check if the bulk element is halo
2574  if (tmp_right_bulk_ele_pt->is_halo())
2575  {
2576  // Then store the corresponding info.
2577  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2578 #ifdef PARANOID
2579  if (right_proc < 0)
2580  {
2581  std::ostringstream error_message;
2582  error_message
2583  << "The current bulk element (right) is marked as halo but "
2584  << "the processor holding\nthe non-halo counterpart is "
2585  << "negative!\n";
2586  throw OomphLibError(error_message.str(),
2587  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2588  OOMPH_EXCEPTION_LOCATION);
2589  }
2590 #endif
2591  // The processor "rank" to the right
2592  unsigned right_processor = static_cast<unsigned>(right_proc);
2593  right_processor_plus_one[is] = right_processor + 1;
2594 
2595  // Now get the id of the halo element to the right
2596  GeneralisedElement *right_element_pt = tmp_right_bulk_ele_pt;
2597 
2598  // Get the halo elements with right processor
2599  Vector<GeneralisedElement*> right_halo_element_pt =
2600  this->halo_element_pt(right_processor);
2601 
2602 #ifdef PARANOID
2603  // Flag to state that the halo element was found
2604  bool right_halo_element_found = false;
2605 #endif
2606 
2607  const unsigned nhalo_right = right_halo_element_pt.size();
2608  for (unsigned rh = 0; rh < nhalo_right; rh++)
2609  {
2610  if (right_element_pt == right_halo_element_pt[rh])
2611  {
2612  right_halo_element[is] = rh;
2613 #ifdef PARANOID
2614  right_halo_element_found = true;
2615 #endif
2616  break;
2617  }
2618  } // for (rh < nhalo_right)
2619 #ifdef PARANOID
2620  if (!right_halo_element_found)
2621  {
2622  std::ostringstream error_message;
2623  error_message
2624  << "The current bulk element (right) marked as halo was not "
2625  << "found in the vector of halo\nelements associated with "
2626  << "the (" << right_processor << ") processor.\n\n";
2627  throw OomphLibError(error_message.str(),
2628  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2629  OOMPH_EXCEPTION_LOCATION);
2630  }
2631 #endif
2632 
2633  // Get the right-most nonhalo element (use the backup list of
2634  // nonhalo elements)
2635  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2636 
2637  // Get the corresponding bulk element
2638  tmp_right_bulk_ele_pt=face_to_bulk_element_pt[right_face_ele_pt];
2639 #ifdef PARANOID
2640  // This element should not be marked as halo
2641  if (tmp_right_bulk_ele_pt->is_halo())
2642  {
2643  std::ostringstream error_message;
2644  error_message
2645  << "The bulk element represetation of the right-most nonhalo face\n"
2646  << "element of the current segment ("<<is<<") is marked as halo,\n"
2647  << "but the face element created from it is nonhalo\n";
2648  throw OomphLibError(error_message.str(),
2649  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2650  OOMPH_EXCEPTION_LOCATION);
2651  } // if (tmp_right_bulk_ele_pt->is_halo())
2652 #endif
2653 
2654  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2655  // to search in the haloed vector
2656  right_element_pt = tmp_right_bulk_ele_pt;
2657 
2658 #ifdef PARANOID
2659  // Flag to state that the haloed element was found
2660  bool right_haloed_element_found = false;
2661 #endif
2662 
2663  // Now get the id for the haloed element to the right
2664  Vector<GeneralisedElement*> right_haloed_element_pt =
2665  this->haloed_element_pt(right_processor);
2666 
2667  const unsigned nhaloed_right = right_haloed_element_pt.size();
2668  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2669  {
2670  if (right_element_pt == right_haloed_element_pt[rhd])
2671  {
2672  right_haloed_element[is] = rhd;
2673 #ifdef PARANOID
2674  right_haloed_element_found = true;
2675 #endif
2676  break;
2677  }
2678  } // for (rhd < nhaloed_right)
2679 
2680 #ifdef PARANOID
2681  if (!right_haloed_element_found)
2682  {
2683  std::ostringstream error_message;
2684  error_message
2685  << "The current bulk element (right) marked as haloed was not "
2686  << "found in the vector of haloed\nelements associated with "
2687  << "the ("<< right_processor << ") processor.\n\n";
2688  throw OomphLibError(error_message.str(),
2689  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2690  OOMPH_EXCEPTION_LOCATION);
2691  }
2692 #endif
2693 
2694  } // if (tmp_right_bulk_ele_pt->is_halo())
2695  else
2696  {
2697  // If not halo then state the info. to indicate that
2698  right_processor_plus_one[is] = 0;
2699  // Null this info.
2700  right_halo_element[is] = 0;
2701  // Null this info.
2702  right_haloed_element[is] = 0;
2703  }
2704 
2705  } // for (is < nsegments). Used to get the halo info. of the
2706  // segments
2707 
2708  // Now we have all the info. to be sent to the root processor and
2709  // compute the correct (global) boundary coordinates for the current
2710  // boundary
2711 
2712  // The root processor will be in charge of performing the computing
2713  // of the coordinate values along the boundary, all the other
2714  // processors only send their info. and wait for receiving the new
2715  // starting values for each of its segments
2716 
2717  // Choose the root processor
2718  const unsigned root_processor = 0;
2719  // ------------------------------------------------------------------
2720  // Starts the MPI stage
2721 
2722  // The root processor receives the number of segments of each
2723  // processor associated to the current boundary
2724  Vector<unsigned> root_nsegments_per_processor(nproc);
2725  unsigned nsegments_mpi = nsegments;
2726  MPI_Gather(&nsegments_mpi, 1, MPI_UNSIGNED,
2727  &root_nsegments_per_processor[0], 1, MPI_UNSIGNED,
2728  root_processor, comm_pt->mpi_comm());
2729 
2730  // Package the info. and prepare it to be sent
2731  // For the packaged info. we send 7 data per each segment, the indexes
2732  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2733  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2734  // segment
2735  // The size of the package (unsigned)
2736  const unsigned spu = 7;
2737  Vector<unsigned> flat_packed_unsigned_send_data(nsegments*spu);
2738  for (unsigned is = 0; is < nsegments; is++)
2739  {
2740  flat_packed_unsigned_send_data[(spu*is)+0]=left_processor_plus_one[is];
2741  flat_packed_unsigned_send_data[(spu*is)+1]=right_processor_plus_one[is];
2742  flat_packed_unsigned_send_data[(spu*is)+2]=left_halo_element[is];
2743  flat_packed_unsigned_send_data[(spu*is)+3]=right_halo_element[is];
2744  flat_packed_unsigned_send_data[(spu*is)+4]=left_haloed_element[is];
2745  flat_packed_unsigned_send_data[(spu*is)+5]=right_haloed_element[is];
2746  flat_packed_unsigned_send_data[(spu*is)+6]=nvertices_per_segment[is];
2747  }
2748 
2749  // How many data will this processor send
2750  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2751 
2752  // How many data does the root processor will receive from each
2753  // processor
2754  Vector<int> root_nudata_to_receive(nproc,0);
2755  // Total number of data to receive from all processors
2756  unsigned root_nutotal_data_receive = 0;
2757  for (unsigned ip = 0; ip < nproc; ip++)
2758  {
2759  // Compute the number of data the root processor will receive from
2760  // each processor
2761  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2762  // Add on the total number of data to receive
2763  root_nutotal_data_receive+= root_nudata_to_receive[ip];
2764  }
2765 
2766  // Stores and compute the offsets (in root) for the data received
2767  // from each processor
2768  Vector<int> root_uoffsets_receive(nproc,0);
2769  root_uoffsets_receive[0] = 0;
2770  for (unsigned ip = 1; ip < nproc; ip++)
2771  {
2772  // Compute the offset to store the values from each processor
2773  root_uoffsets_receive[ip] =
2774  root_uoffsets_receive[ip-1] + root_nudata_to_receive[ip-1];
2775  }
2776 
2777  // Create at least one entry so we don't get a seg fault below
2778  if (flat_packed_unsigned_send_data.size()==0)
2779  {
2780  flat_packed_unsigned_send_data.resize(1);
2781  }
2782 
2783  // Vector where to receive the info.
2784  Vector<unsigned> flat_packed_unsigned_receive_data(
2785  root_nutotal_data_receive);
2786  if (my_rank!=root_processor)
2787  {
2788  // Create at least one entry so we don't get a seg fault below
2789  if (flat_packed_unsigned_receive_data.size()==0)
2790  {
2791  flat_packed_unsigned_receive_data.resize(1);
2792  }
2793  } // if (my_rank!=root_processor)
2794 
2795  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2796  // send info. from
2797  // each processor
2798  nudata_to_send, // Total number of data to send from
2799  // each processor
2800  MPI_UNSIGNED,
2801  &flat_packed_unsigned_receive_data[0], // Container
2802  // where to
2803  // receive the
2804  // info. from all
2805  // the processors
2806  &root_nudata_to_receive[0], // Number of data to receive
2807  // from each processor
2808  &root_uoffsets_receive[0], // The offset to store the
2809  // info. from each processor
2810  MPI_UNSIGNED,
2811  root_processor, //The processor that receives all the
2812  //info.
2813  comm_pt->mpi_comm());
2814 
2815  // Clear the flat package to send
2816  flat_packed_unsigned_send_data.clear();
2817  flat_packed_unsigned_send_data.resize(0);
2818 
2819  // Package the info. and prepare it to be sent
2820  // For the packaged info. we send 1 data per each segment which is
2821  // at the moment the arclength of each segment
2822  // The size of the package
2823  const unsigned spd = 1;
2824  Vector<double> flat_packed_double_send_data(nsegments*spd);
2825  for (unsigned is = 0; is < nsegments; is++)
2826  {
2827  flat_packed_double_send_data[(spd*is)+0]=segment_arclength[is];
2828  }
2829 
2830  // How many data will this processor send
2831  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2832  // How many data does the root processor will receive from each
2833  // processor
2834  Vector<int> root_nddata_to_receive(nproc,0);
2835  // Total number of data to receive from all processors
2836  unsigned root_ndtotal_data_receive = 0;
2837  for (unsigned ip =0; ip < nproc; ip++)
2838  {
2839  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2840  root_ndtotal_data_receive+= root_nddata_to_receive[ip];
2841  }
2842 
2843  // Stores and compute the offsets for the data received from each
2844  // processor
2845  Vector<int> root_doffsets_receive(nproc,0);
2846  root_doffsets_receive[0] = 0;
2847  for (unsigned ip = 1; ip < nproc; ip++)
2848  {
2849  // Compute the offset to store the values from each processor
2850  root_doffsets_receive[ip] =
2851  root_doffsets_receive[ip-1] + root_nddata_to_receive[ip-1];
2852  }
2853 
2854  // Create at least one entry so we don't get a seg fault below
2855  if (flat_packed_double_send_data.size()==0)
2856  {
2857  flat_packed_double_send_data.resize(1);
2858  }
2859 
2860  // Vector where to receive the info.
2861  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2862  if (my_rank!=root_processor)
2863  {
2864  // Create at least one entry so we don't get a seg fault below
2865  if (flat_packed_double_receive_data.size()==0)
2866  {
2867  flat_packed_double_receive_data.resize(1);
2868  }
2869  }
2870 
2871  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2872  // send info. from
2873  // each processor
2874  nddata_to_send, // Total number of data to send from
2875  // each processor
2876  MPI_DOUBLE,
2877  &flat_packed_double_receive_data[0], // Container where
2878  // to receive the
2879  // info. from all
2880  // the processors
2881  &root_nddata_to_receive[0], // Number of data to receive
2882  // from each processor
2883  &root_doffsets_receive[0], // The offset to store the
2884  // info. from each processor
2885  MPI_DOUBLE,
2886  root_processor, //The processor that receives all the
2887  //info.
2888  comm_pt->mpi_comm());
2889 
2890  // Clear the flat package to send
2891  flat_packed_double_send_data.clear();
2892  flat_packed_double_send_data.resize(0);
2893 
2894  // The next three containers are only used by the root processor at
2895  // the end of its computations but it is necessary that all the
2896  // processors know them when calling back the info.
2897 
2898  // Container that state the initial arclength for each segments
2899  // of each processor
2900  Vector<Vector<double> > root_initial_segment_arclength(nproc);
2901 
2902  // Container that state the number of vertices before each segment
2903  // in a given processor
2904  Vector<Vector<unsigned> > root_nvertices_before_segment(nproc);
2905 
2906  // The root processor needs to tell the other processor if it was
2907  // necessary to reverse a segment. Each processor should therefore
2908  // invert the face elements that compose every segment that was
2909  // inverted by the root processor
2910  Vector<Vector<unsigned> > root_segment_inverted(nproc);
2911 
2912  // Used to store the accumulated arclength, used at the end of
2913  // communications to store the total arclength
2914  double root_accumulated_arclength = 0.0;
2915 
2916  // Store the accumulated number of vertices, it means the total number
2917  // of vertices before each segment (counter)
2918  unsigned root_accumulated_vertices_before_segment = 0;
2919 
2920  // The root processor is in charge of performing the connections
2921  // of the segments that define the complete boundary
2922  if (my_rank == root_processor)
2923  {
2924  // From the flat packaged received data re-create the data
2925  // structures storing the info. regarding the connectivity of the
2926  // segments, the number of vertices per segment and the local
2927  // arclength of each segment
2928 
2929  // Stores the "rank" of the processor to the left of each segment,
2930  // zero if there is no processor to the left which states that the
2931  // segment is the first one on the boundary
2932  Vector<Vector<unsigned> > root_left_processor_plus_one(nproc);
2933 
2934  // Stores the "rank" of the processor to the right of each segment,
2935  // zero if there is no processor to the right which states that the
2936  // segment is the last one on the boundary
2937  Vector<Vector<unsigned> > root_right_processor_plus_one(nproc);
2938 
2939  // The id. of the halo element to the left of the segment, note that
2940  // this info. is not necessary if there is no processor to the left
2941  // of the segment or if the processor has no info about the boundary
2942  Vector<Vector<unsigned> > root_left_halo_element(nproc);
2943 
2944  // The id. of the halo element to the right of the segment, note
2945  // that this info. is not necessary if there is no processor to
2946  // the right of the segment or if the processor has no info about
2947  // the boundary
2948  Vector<Vector<unsigned> > root_right_halo_element(nproc);
2949 
2950  // The id. of the haloed element to the left of the segment, note
2951  // that this info. is not necessary if there is no processor to
2952  // the left of the segment or if the processor has no info about
2953  // the boundary
2954  Vector<Vector<unsigned> > root_left_haloed_element(nproc);
2955 
2956  // The id. of the haloed element to the right of the segment, note
2957  // that this info. is not necessary if there is no processor to the
2958  // right of the segment or if the processor has no info about the
2959  // boundary
2960  Vector<Vector<unsigned> > root_right_haloed_element(nproc);
2961 
2962  // The number of vertices per segment in each processor
2963  Vector<Vector<unsigned> > root_nvertices_per_segment(nproc);
2964 
2965  // The arclength of each of the segments in the processors
2966  Vector<Vector<double> > root_segment_arclength(nproc);
2967 
2968  unsigned ucounter = 0;
2969  unsigned dcounter = 0;
2970  for (unsigned ip = 0; ip < nproc; ip++)
2971  {
2972  // Get the number of segments in the current processor
2973  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2974 
2975  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2976  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2977  root_left_halo_element[ip].resize(nsegs_iproc);
2978  root_right_halo_element[ip].resize(nsegs_iproc);
2979  root_left_haloed_element[ip].resize(nsegs_iproc);
2980  root_right_haloed_element[ip].resize(nsegs_iproc);
2981 
2982  // Additional info.
2983  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2984  root_segment_arclength[ip].resize(nsegs_iproc);
2985  root_segment_inverted[ip].resize(nsegs_iproc);
2986 
2987  // Extract the info. from the BIG package received from all
2988  // processors
2989  for(unsigned is = 0; is < nsegs_iproc; is++)
2990  {
2991  // ------ The flat unsigned package ------
2992  root_left_processor_plus_one[ip][is] =
2993  flat_packed_unsigned_receive_data[ucounter++];
2994  root_right_processor_plus_one[ip][is] =
2995  flat_packed_unsigned_receive_data[ucounter++];
2996  root_left_halo_element[ip][is] =
2997  flat_packed_unsigned_receive_data[ucounter++];
2998  root_right_halo_element[ip][is] =
2999  flat_packed_unsigned_receive_data[ucounter++];
3000  root_left_haloed_element[ip][is] =
3001  flat_packed_unsigned_receive_data[ucounter++];
3002  root_right_haloed_element[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_nvertices_per_segment[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006 
3007  // ------ The flat double package ------
3008  root_segment_arclength[ip][is] =
3009  flat_packed_double_receive_data[dcounter++];
3010  } // for (is < nsegs_iproc)
3011  } // for (ip < nproc)
3012 
3013  // Now the root processor has all the info. to find out the
3014  // CONNECTIVITY of the segments in each processor
3015 
3016  // Container that stores the info. related with the connectivity
3017  // of the segments of each processor
3018  Vector<Vector<int> > left_connected_segment_plus_one(nproc);
3019  Vector<Vector<int> > right_connected_segment_plus_one(nproc);
3020  for (unsigned ip = 0; ip < nproc; ip++)
3021  {
3022  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3023  left_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3024  right_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3025  } // for (ip < nprocs)
3026 
3027  // In charge of storing the connectivity of the segments, the pair
3028  // indicates the processor and the segment number
3029  std::list<std::pair<unsigned, unsigned> > proc_seg_connectivity;
3030  proc_seg_connectivity.clear();
3031 
3032  // Done segments on processor
3033  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3034 
3035  // Take the first segment of the first processor with segments and
3036  // add it to the list of segments
3037  unsigned left_proc = 0;
3038  unsigned right_proc = 0;
3039  unsigned left_seg = 0;
3040  unsigned right_seg = 0;
3041  for (unsigned ip = 0; ip < nproc; ip++)
3042  {
3043  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3044  if (nsegs_iproc > 0)
3045  {
3046  right_proc = left_proc = ip;
3047  right_seg = left_seg = 0;
3048  break; // Break because it is the first processor with at
3049  // least one segment
3050  }
3051  } // for (ip < nproc)
3052 
3053  // ... and add it to the list of segments
3054  std::pair<unsigned, unsigned> add_segment =
3055  std::make_pair(left_proc, left_seg);
3056  done_segment[add_segment] = true;
3057  proc_seg_connectivity.push_back(add_segment);
3058 
3059  // Flags to indicate when a segment was added to the left or right
3060  // of the current list of segments
3061  bool added_segment_to_the_left = false;
3062  bool added_segment_to_the_right = false;
3063 
3064  do // while(added_segment_to_the_left || added_segment_to_the_right)
3065  {
3066  // Read the left-most processor and segment in the list
3067  std::pair<unsigned, unsigned> left_pair =
3068  proc_seg_connectivity.front();
3069  left_proc = left_pair.first;
3070  left_seg = left_pair.second;
3071 
3072  // Get the processor number to the left of the left-most
3073  // segment in the list
3074  const unsigned new_left_proc =
3075  root_left_processor_plus_one[left_proc][left_seg];
3076 
3077  if (new_left_proc != 0)
3078  {
3079  // Initialise flag
3080  added_segment_to_the_left = false;
3081  // Get the left halo element id
3082  const unsigned left_halo_id =
3083  root_left_halo_element[left_proc][left_seg];
3084 
3085  // Get the left haloed element id
3086  const unsigned left_haloed_id =
3087  root_left_haloed_element[left_proc][left_seg];
3088 
3089  // Go through the segments on the new left processor and look
3090  // for the corresponding left_halo_id in the haloed_ids
3091  const unsigned nsegs_new_left_proc =
3092  root_nsegments_per_processor[new_left_proc-1];
3093 
3094  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3095  {
3096  std::pair<unsigned, unsigned> candidate_seg =
3097  std::make_pair(new_left_proc-1, ils);
3098 
3099  // Check that the segment has not been already added
3100  if (!done_segment[candidate_seg])
3101  {
3102  // Only consider the segments on new left processor which
3103  // right processor is the current one (left_proc)
3104  const unsigned right_proc_of_new_left_proc =
3105  root_right_processor_plus_one[new_left_proc-1][ils];
3106  // Also get the left_proc_of_new_left_proc (in case that it
3107  // be necessary to invert the segment)
3108  const unsigned left_proc_of_new_left_proc =
3109  root_left_processor_plus_one[new_left_proc-1][ils];
3110  // Check the not inverted case (to the left and not
3111  // inverted)
3112  if (right_proc_of_new_left_proc != 0 &&
3113  right_proc_of_new_left_proc-1 == left_proc)
3114  {
3115  // Get the haloed/haloed element id of the current segment
3116  // in the new left processor and compare it to the
3117  // halo/haloed element id of the left_processor
3118  const unsigned right_halo_id =
3119  root_right_halo_element[new_left_proc-1][ils];
3120  const unsigned right_haloed_id =
3121  root_right_haloed_element[new_left_proc-1][ils];
3122  if (left_halo_id == right_haloed_id &&
3123  left_haloed_id == right_halo_id)
3124  {
3125  // We have a match of the segments (store the segment
3126  // number plus one on the processor to the left)
3127  left_connected_segment_plus_one[left_proc][left_seg]=
3128  ils+1;
3129  // Add the pair to the connectivity list
3130  proc_seg_connectivity.push_front(candidate_seg);
3131  added_segment_to_the_left = true;
3132  break;
3133  }
3134  } // if (right_proc_of_new_left_proc-1 == left_proc)
3135 
3136  // Check the inverted case (to the left and inverted)
3137  if (left_proc_of_new_left_proc != 0 &&
3138  left_proc_of_new_left_proc-1 == left_proc)
3139  {
3140  // Get the haloed element id of the current segment
3141  // (inverted version) in the new left processor and
3142  // compare it to the halo element id of the left_processor
3143  const unsigned inv_left_halo_id =
3144  root_left_halo_element[new_left_proc-1][ils];
3145  const unsigned inv_left_haloed_id =
3146  root_left_haloed_element[new_left_proc-1][ils];
3147  if (left_halo_id == inv_left_haloed_id &&
3148  left_haloed_id == inv_left_halo_id)
3149  {
3150  // We have a match of the segments (store the segment
3151  // number plus one on the processor to the left)
3152  left_connected_segment_plus_one[left_proc][left_seg]=
3153  ils+1;
3154  // Add the pair to the connectivity list
3155  proc_seg_connectivity.push_front(candidate_seg);
3156 
3157  // In addition to the connectivity we need to invert the
3158  // segment (the information)
3159  const unsigned tmp_proc =
3160  root_left_processor_plus_one[new_left_proc-1][ils];
3161  const unsigned tmp_halo =
3162  root_left_halo_element[new_left_proc-1][ils];
3163  const unsigned tmp_haloed =
3164  root_left_haloed_element[new_left_proc-1][ils];
3165 
3166  root_left_processor_plus_one[new_left_proc-1][ils] =
3167  root_right_processor_plus_one[new_left_proc-1][ils];
3168  root_left_halo_element[new_left_proc-1][ils] =
3169  root_right_halo_element[new_left_proc-1][ils];
3170  root_left_haloed_element[new_left_proc-1][ils] =
3171  root_right_haloed_element[new_left_proc-1][ils];
3172 
3173  root_right_processor_plus_one[new_left_proc-1][ils] =
3174  tmp_proc;
3175  root_right_halo_element[new_left_proc-1][ils]=tmp_halo;
3176  root_right_haloed_element[new_left_proc-1][ils] =
3177  tmp_haloed;
3178 
3179  // ... and mark the segment as inverted in the root
3180  // processor to inform back to the owner processor
3181  root_segment_inverted[new_left_proc-1][ils] = 1;
3182 
3183  added_segment_to_the_left = true;
3184  break;
3185  }
3186  } // if (left_proc_of_new_left_proc-1 == left_proc)
3187  } // if (!done_segment[candidate_segment])
3188  } // for (ils < nsegs_new_left_proc)
3189 
3190 #ifdef PARANOID
3191  if (!added_segment_to_the_left)
3192  {
3193  std::ostringstream error_message;
3194  error_message
3195  << "The corresponding processor and segment to the left of "
3196  << "the current left\nmost segment was not found\n";
3197  throw OomphLibError(error_message.str(),
3198  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3199  OOMPH_EXCEPTION_LOCATION);
3200  }
3201 #endif
3202  } // if (new_left_proc != 0)
3203  else
3204  {
3205  // No more segments to the left
3206  added_segment_to_the_left = false;
3207  }
3208 
3209  // Read the info. of the right processor and the right segment
3210  std::pair<unsigned, unsigned> right_pair =
3211  proc_seg_connectivity.back();
3212  right_proc = right_pair.first;
3213  right_seg = right_pair.second;
3214 
3215  // Get the processor number to the right of the right-most
3216  // segment in the list
3217  const unsigned new_right_proc =
3218  root_right_processor_plus_one[right_proc][right_seg];
3219 
3220  if (new_right_proc != 0)
3221  {
3222  // Initialise flag
3223  added_segment_to_the_right = false;
3224  // Get the right halo element id
3225  const unsigned right_halo_id =
3226  root_right_halo_element[right_proc][right_seg];
3227 
3228  // Get the right halo element id
3229  const unsigned right_haloed_id =
3230  root_right_haloed_element[right_proc][right_seg];
3231 
3232  // Go through the segments on the new right processor and look
3233  // for the corresponding right_halo_id in the haloed_ids
3234  const unsigned nsegs_new_right_proc =
3235  root_nsegments_per_processor[new_right_proc-1];
3236 
3237  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3238  {
3239  std::pair<unsigned, unsigned> candidate_seg =
3240  std::make_pair(new_right_proc-1, irs);
3241 
3242  // Check that the segment has not been already added
3243  if (!done_segment[candidate_seg])
3244  {
3245  // Only consider the segments on new right processor which
3246  // left processor is the current one (right_proc)
3247  const unsigned left_proc_of_new_right_proc =
3248  root_left_processor_plus_one[new_right_proc-1][irs];
3249  // Also get the right_proc_of_new_right_proc (in case
3250  // that it be necessary to invert the segment)
3251  const unsigned right_proc_of_new_right_proc =
3252  root_right_processor_plus_one[new_right_proc-1][irs];
3253  // Check the not inverted case (to the right and not
3254  // inverted)
3255  if (left_proc_of_new_right_proc != 0 &&
3256  left_proc_of_new_right_proc-1 == right_proc)
3257  {
3258  // Get the haloed element id of the current segment in the
3259  // new right processor and compare it to the halo element
3260  // id of the right_processor
3261  const unsigned left_halo_id =
3262  root_left_halo_element[new_right_proc-1][irs];
3263  const unsigned left_haloed_id =
3264  root_left_haloed_element[new_right_proc-1][irs];
3265 
3266  if (right_halo_id == left_haloed_id &&
3267  right_haloed_id == left_halo_id)
3268  {
3269  // We have a match of the segments (store the segment
3270  // number plus one on the processor to the right)
3271  right_connected_segment_plus_one[right_proc][right_seg]=
3272  irs+1;
3273  // Add the connectivity information to the list
3274  proc_seg_connectivity.push_back(candidate_seg);
3275  added_segment_to_the_right = true;
3276  break;
3277  }
3278  } // if (left_proc_of_new_right_proc-1 == right_proc)
3279 
3280  // Check the inverted case (to the right and inverted)
3281  if (right_proc_of_new_right_proc != 0 &&
3282  right_proc_of_new_right_proc-1 == right_proc)
3283  {
3284  // Get the haloed element id of the current segment
3285  // (inverted version) in the new right processor and
3286  // compare it to the halo element id of the
3287  // right_processor
3288  const unsigned inv_right_halo_id =
3289  root_right_halo_element[new_right_proc-1][irs];
3290  const unsigned inv_right_haloed_id =
3291  root_right_haloed_element[new_right_proc-1][irs];
3292  if (right_halo_id == inv_right_haloed_id &&
3293  right_haloed_id == inv_right_halo_id)
3294  {
3295  // We have a match of the segments (store the segment
3296  // number plus one on the processor to the right)
3297  right_connected_segment_plus_one[right_proc][right_seg]=
3298  irs+1;
3299  // Add the connectivity information to the list
3300  proc_seg_connectivity.push_back(candidate_seg);
3301  // In addition to the connectivity we need to invert the
3302  // segment
3303  const unsigned tmp_proc =
3304  root_left_processor_plus_one[new_right_proc-1][irs];
3305  const unsigned tmp_halo =
3306  root_left_halo_element[new_right_proc-1][irs];
3307  const unsigned tmp_haloed =
3308  root_left_haloed_element[new_right_proc-1][irs];
3309 
3310  root_left_processor_plus_one[new_right_proc-1][irs] =
3311  root_right_processor_plus_one[new_right_proc-1][irs];
3312  root_left_halo_element[new_right_proc-1][irs] =
3313  root_right_halo_element[new_right_proc-1][irs];
3314  root_left_haloed_element[new_right_proc-1][irs] =
3315  root_right_haloed_element[new_right_proc-1][irs];
3316 
3317  root_right_processor_plus_one[new_right_proc-1][irs] =
3318  tmp_proc;
3319  root_right_halo_element[new_right_proc-1][irs]=tmp_halo;
3320  root_right_haloed_element[new_right_proc-1][irs] =
3321  tmp_haloed;
3322 
3323  // ... and mark the segment as inverted in the root
3324  // processor to inform back to the owner processor
3325  root_segment_inverted[new_right_proc-1][irs] = 1;
3326 
3327  added_segment_to_the_right = true;
3328  break;
3329  }
3330  } // if (right_proc_of_new_right_proc-1 == right_proc)
3331  } // if (!done_segment[candidate_segment])
3332  } // for (irs < nsegs_new_left_proc)
3333 
3334 #ifdef PARANOID
3335  if (!added_segment_to_the_right)
3336  {
3337  std::ostringstream error_message;
3338  error_message
3339  << "The corresponding processor and segment to the right of "
3340  << "the current right\nmost segment was not found\n";
3341  throw OomphLibError(error_message.str(),
3342  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3343  OOMPH_EXCEPTION_LOCATION);
3344  }
3345 #endif
3346  } // if (new_right_proc != 0)
3347  else
3348  {
3349  // No more segments to the left
3350  added_segment_to_the_right = false;
3351  }
3352 
3353  }while(added_segment_to_the_left || added_segment_to_the_right);
3354 
3355  // Once we have connected the segments then we can compute the
3356  // initial and final zeta values based on the arclength of each
3357  // individual segment
3358 
3359  // Get the total number of segments, which MUST be the same as the
3360  // total number of segments in all processors
3361  const unsigned ntotal_segments = proc_seg_connectivity.size();
3362 #ifdef PARANOID
3363  unsigned tmp_total_segments = 0;
3364  for (unsigned ip =0; ip < nproc; ip++)
3365  {
3366  tmp_total_segments+= root_nsegments_per_processor[ip];
3367  }
3368 
3369  // Check that the total number of segments in all processors is
3370  // the same as the number of segments that form the boundary
3371  if (ntotal_segments!=tmp_total_segments)
3372  {
3373  std::ostringstream error_message;
3374  error_message
3375  << "The number of sorted segments (" << ntotal_segments << ") on "
3376  << "boundary ("<< b <<")\nis different from the total number of "
3377  <<"segments ("<< tmp_total_segments <<") in all\nprocessors.\n\n";
3378  throw OomphLibError(error_message.str(),
3379  OOMPH_CURRENT_FUNCTION,
3380  OOMPH_EXCEPTION_LOCATION);
3381  } // if (ntotal_segments!=tmp_total_segments)
3382 #endif
3383 
3384  // Now that we know the connectivity of the segments we can
3385  // compute the initial arclength of each segment in the
3386  // processors. Additionally we also get the number of vertices
3387  // before each of the segments. Resize the containers considering
3388  // the number of segments in each processor
3389  for (unsigned ip = 0; ip < nproc; ip++)
3390  {
3391  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3392  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3393  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3394  }
3395 
3396  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3397  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3398 
3399  ucounter = 0;
3400  for (std::list<std::pair<unsigned, unsigned> >::iterator
3401  it_list = proc_seg_connectivity.begin();
3402  it_list != proc_seg_connectivity.end(); it_list++)
3403  {
3404  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3405  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3406  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3407  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3408 
3409  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3410  aux_nvertices_before_segment[ucounter] =
3411  root_accumulated_vertices_before_segment;
3412 
3413  // Set the initial zeta value for the segment
3414  root_initial_segment_arclength[iproc][iseg] = root_accumulated_arclength;
3415  // Set the number of vertices before the current segment
3416  root_nvertices_before_segment[iproc][iseg] =
3417  root_accumulated_vertices_before_segment;
3418 
3419  // Add the arclength of the segment to the global arclength
3420  root_accumulated_arclength+= iseg_arclength;
3421  // Add the number of vertices to the global number of vertices
3422  root_accumulated_vertices_before_segment+= iseg_nvertices - 1;
3423 
3424  // Increase the counter
3425  ucounter++;
3426  } // for (loop over the sorted segments to assigne initial
3427  // arlength and initial number of vertices)
3428 
3429  // Increase by one to get the total number of vertices on the
3430  // boundary
3431  root_accumulated_vertices_before_segment++;
3432 
3433  // Get the processors with the initial and final segment.
3434  proc_with_initial_seg = proc_seg_connectivity.front().first;
3435  proc_with_final_seg = proc_seg_connectivity.back().first;
3436  // Also get the corresponding initial and final segment indexes
3437  // (on the initial and final processors)
3438  initial_segment = proc_seg_connectivity.front().second;
3439  final_segment = proc_seg_connectivity.back().second;
3440 
3441  } // if (my_rank == root_processor)
3442 
3443  // Get the total number of segments
3444  unsigned root_ntotal_segments = 0;
3445  for (unsigned ip =0; ip < nproc; ip++)
3446  {
3447  root_ntotal_segments+= root_nsegments_per_processor[ip];
3448  }
3449 
3450  // Package the info. that will be sent to each processor. For the
3451  // unsigned package we send the number of vertices before each
3452  // segment in each processor and whether it was inverted or not
3453  // Package size
3454  const unsigned rspu = 2;
3455  flat_packed_unsigned_send_data.clear();
3456  flat_packed_unsigned_send_data.resize(root_ntotal_segments*rspu);
3457  unsigned ucounter = 0;
3458  // Collect the info. from all the segments in the processors
3459  for (unsigned ip = 0; ip < nproc; ip++)
3460  {
3461  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3462  for (unsigned is = 0; is < nsegs_iproc; is++)
3463  {
3464  flat_packed_unsigned_send_data[ucounter++] =
3465  root_nvertices_before_segment[ip][is];
3466  flat_packed_unsigned_send_data[ucounter++] =
3467  root_segment_inverted[ip][is];
3468  } // for (is < nsegs_iproc)
3469  } // for (ip < nproc)
3470 
3471  // How many data does the root processor will send to each processor
3472  Vector<int> root_nudata_to_send(nproc,0);
3473  for (unsigned ip =0; ip < nproc; ip++)
3474  {
3475  // Get the number of data to send to ip processor
3476  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3477  }
3478 
3479  // Store and compute the offsets for the data sent to each processor
3480  Vector<int> root_uoffsets_send(nproc,0);
3481  root_uoffsets_send[0] = 0;
3482  for (unsigned ip = 1; ip < nproc; ip++)
3483  {
3484  // Compute the offset to send the values to each processor
3485  root_uoffsets_send[ip] =
3486  root_uoffsets_send[ip-1] + root_nudata_to_send[ip-1];
3487  }
3488 
3489  // Number of data to receive from root
3490  unsigned nutotal_data_receive = nsegments * rspu;
3491 
3492  if (my_rank!=root_processor)
3493  {
3494  // Create at least one entry so we don't get a seg fault below
3495  if (flat_packed_unsigned_send_data.size()==0)
3496  {
3497  flat_packed_unsigned_send_data.resize(1);
3498  }
3499  }
3500 
3501  // Clear and resize the vector where to receive the info.
3502  flat_packed_unsigned_receive_data.clear();
3503  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3504  // Create at least one entry so we don't get a seg fault below
3505  if (flat_packed_unsigned_receive_data.size()==0)
3506  {
3507  flat_packed_unsigned_receive_data.resize(1);
3508  }
3509 
3510  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3511  &root_nudata_to_send[0],
3512  &root_uoffsets_send[0],
3513  MPI_UNSIGNED,
3514  &flat_packed_unsigned_receive_data[0],
3515  nutotal_data_receive,
3516  MPI_UNSIGNED,
3517  root_processor,
3518  comm_pt->mpi_comm());
3519 
3520  // Package the info. that will be sent to each processor, for the
3521  // double package we send (one data per segment) the initial
3522  // arclength for each segment
3523  const unsigned rspd = 1;
3524  flat_packed_double_send_data.clear();
3525  flat_packed_double_send_data.resize(root_ntotal_segments*rspd);
3526  unsigned dcounter = 0;
3527  // Collect the info. from all the segments in the processors
3528  for (unsigned ip = 0; ip < nproc; ip++)
3529  {
3530  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3531  for (unsigned is = 0; is < nsegs_iproc; is++)
3532  {
3533  flat_packed_double_send_data[dcounter++] =
3534  root_initial_segment_arclength[ip][is];
3535  }
3536  }
3537 
3538  // How many data does the root processor will send to each processor
3539  Vector<int> root_nddata_to_send(nproc,0);
3540  for (unsigned ip =0; ip < nproc; ip++)
3541  {
3542  // Number of data send to ip processor
3543  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3544  }
3545 
3546  // Store and compute the offsets for the data sent to each processor
3547  Vector<int> root_doffsets_send(nproc,0);
3548  root_doffsets_send[0] = 0;
3549  for (unsigned ip = 1; ip < nproc; ip++)
3550  {
3551  // Compute the offset to send the values to each processor
3552  root_doffsets_send[ip] =
3553  root_doffsets_send[ip-1] + root_nddata_to_send[ip-1];
3554  }
3555 
3556  // Number of double data to receive from root
3557  unsigned ndtotal_data_receive = nsegments * rspd;
3558 
3559  if (my_rank!=root_processor)
3560  {
3561  // Create at least one entry so we don't get a seg fault below
3562  if (flat_packed_double_send_data.size()==0)
3563  {
3564  flat_packed_double_send_data.resize(1);
3565  }
3566  }
3567 
3568  // Clear and resize the vector where to receive the info.
3569  flat_packed_double_receive_data.clear();
3570  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3571  // Create at least one entry so we don't get a seg fault below
3572  if (flat_packed_double_receive_data.size()==0)
3573  {
3574  flat_packed_double_receive_data.resize(1);
3575  }
3576 
3577  MPI_Scatterv(&flat_packed_double_send_data[0],
3578  &root_nddata_to_send[0],
3579  &root_doffsets_send[0],
3580  MPI_DOUBLE,
3581  &flat_packed_double_receive_data[0],
3582  ndtotal_data_receive,
3583  MPI_DOUBLE,
3584  root_processor,
3585  comm_pt->mpi_comm());
3586 
3587  // Read if the segments need to be inverted and read the initial
3588  // arclengths
3589  ucounter = 0;
3590  dcounter = 0;
3591 
3592  // Read the info. from the flat package and store it in their
3593  // corresponding containers
3594  for (unsigned is = 0; is < nsegments; is++)
3595  {
3596  // The flat unsigned package
3597  nvertices_before_segment[is] =
3598  flat_packed_unsigned_receive_data[ucounter++];
3599  // The segment inverted flag
3600  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3601  // The flat double package
3602  initial_segment_arclength[is] =
3603  flat_packed_double_receive_data[dcounter++];
3604  } // for (is < nsegments)
3605 
3606  // Perform two additional communications to get the total number of
3607  // vertices, the processors with the initial and final segments, the
3608  // corresponding initial and final segments ...
3609  const unsigned numore_info = 5;
3610  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3611  // Prepare the info ...
3612  flat_package_unsigned_more_info[0] = root_accumulated_vertices_before_segment;
3613  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3614  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3615  flat_package_unsigned_more_info[3] = initial_segment;
3616  flat_package_unsigned_more_info[4] = final_segment;
3617 
3618  // Send the info. to all processors
3619  MPI_Bcast(&flat_package_unsigned_more_info[0], numore_info,
3620  MPI_UNSIGNED, root_processor, comm_pt->mpi_comm());
3621 
3622  // ... and store the info. in the proper containers
3623  root_accumulated_vertices_before_segment = flat_package_unsigned_more_info[0];
3624  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3625  proc_with_final_seg = flat_package_unsigned_more_info[2];
3626  initial_segment = flat_package_unsigned_more_info[3];
3627  final_segment = flat_package_unsigned_more_info[4];
3628 
3629  // Do the same for the maximum zeta value
3630  MPI_Bcast(&root_accumulated_arclength, 1, MPI_DOUBLE,
3631  root_processor, comm_pt->mpi_comm());
3632 
3633  // -----------------------------------------------------------------
3634  // Clear the storage to store the data that will be used by the
3635  // setup boundary coordinates method, if we do not perform the
3636  // cleaning then previous data from previous iterations will remain
3637  // there
3638  // -----------------------------------------------------------------
3639  // The info. for the boundary
3640  Boundary_initial_coordinate[b].clear();
3641  Boundary_final_coordinate[b].clear();
3642 
3643  Boundary_initial_zeta_coordinate[b].clear();
3644  Boundary_final_zeta_coordinate[b].clear();
3645 
3646  // The info. for the segments
3647  Boundary_segment_inverted[b].clear();
3648  Boundary_segment_initial_coordinate[b].clear();
3649  Boundary_segment_final_coordinate[b].clear();
3650 
3651  Boundary_segment_initial_zeta[b].clear();
3652  Boundary_segment_final_zeta[b].clear();
3653 
3654  Boundary_segment_initial_arclength[b].clear();
3655  Boundary_segment_final_arclength[b].clear();
3656 
3657  // Now copy all the info. to the containers to be sent to any other
3658  // mesh (in the adaptation method)
3659  for (unsigned is = 0; is < nsegments; is++)
3660  {
3661  // At this point we can get the initial and final coordinates for
3662  // each segment
3663  Vector<double> first_seg_coord(2);
3664  Vector<double> last_seg_coord(2);
3665 
3666  // In order to get the first and last coordinates of each segment we
3667  // first need to identify the first and last nonhalo element of each
3668  // segment, and then get the first and last node of the segment
3669 
3670  // Get the first nonhalo face element on the segment
3671  FiniteElement* first_seg_ele_pt =
3672  segment_sorted_nonhalo_ele_pt[is].front();
3673 
3674 #ifdef PARANOID
3675  // Check if the face element is nonhalo, it shouldn't, but better
3676  // check
3677  if (first_seg_ele_pt->is_halo())
3678  {
3679  std::ostringstream error_message;
3680  error_message
3681  << "The first face element in the (" << is << ")-th segment is halo\n";
3682  throw OomphLibError(error_message.str(),
3683  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3684  OOMPH_EXCEPTION_LOCATION);
3685  } // if (tmp_first_bulk_ele_pt->is_halo())
3686 #endif
3687 
3688  // Number of nodes
3689  const unsigned nnod = first_seg_ele_pt->nnode();
3690 
3691  // Get the first node of the current segment
3692  Node *first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3693  if (is_inverted[first_seg_ele_pt])
3694  {
3695  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);
3696  }
3697 
3698  // Get the last nonhalo face element on the segment
3699  FiniteElement* last_seg_ele_pt =
3700  segment_sorted_nonhalo_ele_pt[is].back();
3701 
3702 #ifdef PARANOID
3703  // Check if the face element is nonhalo, it shouldn't, but better
3704  // check
3705  if (last_seg_ele_pt->is_halo())
3706  {
3707  std::ostringstream error_message;
3708  error_message
3709  << "The last face element in the (" << is << ")-th segment is halo\n";
3710  throw OomphLibError(error_message.str(),
3711  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3712  OOMPH_EXCEPTION_LOCATION);
3713  } // if (tmp_first_bulk_ele_pt->is_halo())
3714 #endif
3715 
3716  // Get the last node of the current segment
3717  Node *last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
3718  if (is_inverted[last_seg_ele_pt])
3719  {
3720  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3721  }
3722 
3723  // Get the coordinates for the first and last segment's node
3724  for (unsigned i = 0; i < 2; i++)
3725  {
3726  first_seg_coord[i] = first_seg_node_pt->x(i);
3727  last_seg_coord[i] = last_seg_node_pt->x(i);
3728  }
3729 
3730  // -----------------------------------------------------------------
3731  // Copy the info. if the segment is inverted
3732  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3733 
3734  // Check if the segment is inverted, if that is the case then invert
3735  // the first and last seg. coordinates
3736  if (!segment_inverted[is])
3737  {
3738  // Store the initial and final coordinates that will help to
3739  // identify the segments in the new meshes created from this one
3740  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3741  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3742  }
3743  else
3744  {
3745  // Store the initial and final coordinates that will help to
3746  // identify the segments in the new meshes created from this one
3747  // Invert the initial and final coordinates
3748  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3749  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3750  }
3751 
3752  // Now assign initial and final zeta boundary coordinates for each
3753  // segment
3754  // -----------------------------------------------------------------
3755  // If there is a geom object then
3756  if (boundary_geom_object_pt(b)!=0)
3757  {
3758  // Store the initial and final zeta for the current segments (we
3759  // got this when we assigned arclength to the segments in the
3760  // current processor)
3761  if (segment_inverted[is])
3762  {
3763  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3764  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3765  }
3766  else
3767  {
3768  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3769  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3770  }
3771  } // if (boundary_geom_object_pt(b)!=0)
3772  else
3773  {
3774  // Store the initial arclength and vertices number for the
3775  // current segment
3776  Boundary_segment_initial_arclength[b].push_back(
3777  initial_segment_arclength[is]);
3778 
3779  Boundary_segment_final_arclength[b].push_back(
3780  initial_segment_arclength[is] + segment_arclength[is]);
3781 
3782  } // else if (boundary_geom_object_pt(b)!=0)
3783 
3784  } // // for (is < nsegments)
3785 
3786  // Get the number of segments from the sets of nodes
3787 #ifdef PARANOID
3788  if (segment_all_nodes_pt.size() != nsegments)
3789  {
3790  std::ostringstream error_message;
3791  error_message
3792  <<"The number of segments ("<<nsegments<<") and the number of "
3793  <<"set of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
3794  <<"the\nsegments is different!!!\n\n";
3795  throw OomphLibError(error_message.str(),
3796  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3797  OOMPH_EXCEPTION_LOCATION);
3798  }
3799 #endif
3800 
3801  // The nodes have been assigned arc-length coordinates from one end
3802  // or the other of the connected segment.
3803 
3804  // -----------------------------------------------------------------
3805  // If mesh is distributed get the info. regarding the initial and
3806  // final nodes coordinates on the boundary, same as the zeta
3807  // boundary values for those nodes
3808 
3809  // Storage for the coordinates of the first and last nodes on the
3810  // boundary
3811  Vector<double> first_coordinate(2);
3812  Vector<double> last_coordinate(2);
3813 
3814  // Storage for the zeta coordinate of the first and last nodes on
3815  // the boundary
3816  Vector<double> first_node_zeta_coordinate(1,0.0);
3817  Vector<double> last_node_zeta_coordinate(1,0.0);
3818 
3819  // Send three data to all processors, the x[0], x[1] coordinate and
3820  // the zeta coordinate
3821  const unsigned ndtotal_data = 3;
3822  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3823 
3824  // If the mesh is distributed then check if this processor has the
3825  // initial segment
3826  if (my_rank == proc_with_initial_seg)
3827  {
3828  // Stores the firts element of the segment
3829  FiniteElement* first_ele_pt = 0;
3830  // Stores the first node of the boundary
3831  Node *first_node_pt = 0;
3832  // Check if the segment is inverted
3833  if (!segment_inverted[initial_segment])
3834  {
3835  // Get access to the first element on the segment marked as
3836  // initial
3837  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3838 
3839  // Number of nodes
3840  const unsigned nnod = first_ele_pt->nnode();
3841 
3842  // Get the first node of the current segment
3843  first_node_pt = first_ele_pt->node_pt(0);
3844  if (is_inverted[first_ele_pt])
3845  {
3846  first_node_pt = first_ele_pt->node_pt(nnod-1);
3847  }
3848  } // if (!segment_inverted[initial_segment])
3849  else
3850  {
3851  // Get access to the first element on the segment marked as
3852  // initial
3853  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3854 
3855  // Number of nodes
3856  const unsigned nnod = first_ele_pt->nnode();
3857 
3858  // Get the first node of the current segment
3859  first_node_pt = first_ele_pt->node_pt(nnod-1);
3860  if (is_inverted[first_ele_pt])
3861  {
3862  first_node_pt = first_ele_pt->node_pt(0);
3863  }
3864  } // else if (!segment_inverted[initial_segment])
3865 
3866  // Get the coordinates for the first node
3867  for (unsigned i = 0; i < 2; i++)
3868  {
3869  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3870  }
3871 
3872  // Get the zeta coordinates for the first node
3873  Vector<double> tmp_zeta(1);
3874  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3875 
3876  // If there is a geometric object associated to the boundary then
3877  // further process is necessary
3878  if (this->boundary_geom_object_pt(b)!=0)
3879  {
3880  //tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3881  }
3882  else
3883  {
3884  // Check if the initial boundary coordinate is different from
3885  // zero, if that is the case then we need to set it to zero
3886  if (tmp_zeta[0] >= 1.0e-14)
3887  {
3888  tmp_zeta[0]=0;
3889  }
3890  } // if (this->boundary_geom_object_pt(b)!=0)
3891 
3892  // Store the initial zeta value
3893  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3894 
3895  } // if (my_rank == proc_with_initial_seg)
3896 
3897  // All processor receive the info. from the processor that has the
3898  // initial segment
3899  MPI_Bcast(&flat_packed_double_data_initial_seg[0], ndtotal_data,
3900  MPI_DOUBLE, proc_with_initial_seg, comm_pt->mpi_comm());
3901 
3902  // ... and all processor put that info. into the appropriate
3903  // storages
3904  for (unsigned i = 0; i < 2; i++)
3905  {
3906  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3907  }
3908  first_node_zeta_coordinate[0]=flat_packed_double_data_initial_seg[2];
3909 
3910  // -----------------------------------------------------------------
3911  // Send three data to all processors, the x[0], x[1] coordinate and
3912  // the zeta coordinate
3913  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3914 
3915  // If the mesh is distributed then check if this processor has the
3916  // final segment
3917  if (my_rank == proc_with_final_seg)
3918  {
3919  // Get access to the last element on the segment
3920  FiniteElement* last_ele_pt = 0;
3921 
3922  // Get the last node of the current segment
3923  Node *last_node_pt = 0;
3924 
3925  // Check if the segment is inverted
3926  if (!segment_inverted[final_segment])
3927  {
3928  // Get access to the last element on the segment marked as
3929  // final
3930  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3931 
3932  // Number of nodes
3933  const unsigned nnod = last_ele_pt->nnode();
3934 
3935  // Get the last node of the current segment
3936  last_node_pt = last_ele_pt->node_pt(nnod-1);
3937  if (is_inverted[last_ele_pt])
3938  {
3939  last_node_pt = last_ele_pt->node_pt(0);
3940  }
3941  } // if (!segment_inverted[final_segment])
3942  else
3943  {
3944  // Get access to the first element on the segment marked as
3945  // initial
3946  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3947 
3948  // Number of nodes
3949  const unsigned nnod = last_ele_pt->nnode();
3950 
3951  // Get the first node of the current segment
3952  last_node_pt = last_ele_pt->node_pt(0);
3953  if (is_inverted[last_ele_pt])
3954  {
3955  last_node_pt = last_ele_pt->node_pt(nnod-1);
3956  }
3957  } // if (!segment_inverted[final_segment])
3958 
3959  // Get the coordinates for the last node
3960  for (unsigned i = 0; i < 2; i++)
3961  {
3962  flat_packed_double_data_final_seg[i]=last_node_pt->x(i);
3963  }
3964 
3965  // Get the zeta coordinates for the last node
3966  Vector<double> tmp_zeta(1);
3967  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3968 
3969  // If there is not a geometric object associated to the boundary
3970  // then further process is required
3971  if (this->boundary_geom_object_pt(b)!=0)
3972  {
3973  // Do nothing
3974  } // if (this->boundary_geom_object_pt(b)!=0)
3975  else
3976  {
3977  // Check if the final boundary coordinate is different from
3978  // the boundary arclength, if that is the case then we need
3979  // to set it to the accumulated arclength
3980  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
3981  {
3982  tmp_zeta[0] = root_accumulated_arclength;
3983  }
3984  } // else if (this->boundary_geom_object_pt(b)!=0)
3985 
3986  // Store the final zeta value
3987  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
3988 
3989  } // if (my_rank == proc_with_final_seg)
3990 
3991  // All processor receive the info. from the processor that has the
3992  // final segment
3993  MPI_Bcast(&flat_packed_double_data_final_seg[0], ndtotal_data,
3994  MPI_DOUBLE, proc_with_final_seg, comm_pt->mpi_comm());
3995 
3996  // All processor receive the info. from the processor that has the
3997  // final segment
3998  for (unsigned i = 0; i < 2; i++)
3999  {
4000  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4001  }
4002  last_node_zeta_coordinate[0]=flat_packed_double_data_final_seg[2];
4003 
4004  // -----------------------------------------------------------------
4005  // Copy the values to the permanent storage
4006  Boundary_initial_coordinate[b] = first_coordinate;
4007  Boundary_final_coordinate[b] = last_coordinate;
4008 
4009  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4010  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4011 
4012  // If we are dealing with an internal boundary then re-assign the
4013  // initial and final zeta values for the segments
4014  if (is_internal_boundary)
4015  {
4016  // Only re-assign zeta values if there are at least one nonhalo
4017  // segment, if all the possible segments are halo then the
4018  // synchronisation method will be in charge of assigning the
4019  // correct boundary coordinates
4020  if (nsegments > 0)
4021  {
4022  // Call the following method to re-construct the segments but
4023  // using only the nonhalo elements, therefore the boundary
4024  // coordinates need to be re-assigned
4025  re_assign_initial_zeta_values_for_internal_boundary(
4026  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4027  }
4028 
4029  } // if (is_internal_boundary)
4030 
4031  // Now identify the boundary segments
4032  if (nsegments > 0)
4033  {
4034  // Identify the boundary segments in the current mesh
4035  //identify_boundary_segments_and_assign_initial_zeta_values(
4036  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4037  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
4038  } // if (nsegments > 0)
4039 
4040  // Clean all the created face elements
4041  for (unsigned i = 0; i < n_all_face_ele; i++)
4042  {
4043  delete all_face_ele_pt[i];
4044  all_face_ele_pt[i] = 0;
4045  }
4046 
4047  }
4048 
4049  //======================================================================
4050  /// \short Re-assign the boundary segments initial zeta (arclength)
4051  /// for those internal boundaries that were splited during the
4052  /// distribution process. Those boundaries that have one face element
4053  /// at each side of the boundary. Here we create the segments only
4054  /// with the nonhalo elements, therefore the boundary coordinates
4055  /// need to be re-assigned to be passed to the new meshes
4056  //======================================================================
4057  template<class ELEMENT>
4060  const unsigned& b,
4061  Vector<std::list<FiniteElement*> > &old_segment_sorted_ele_pt,
4062  std::map<FiniteElement*, bool> &old_is_inverted)
4063  {
4064  // ------------------------------------------------------------------
4065  // First: Get the face elements associated with the current boundary
4066  // Only include nonhalo face elements
4067  // ------------------------------------------------------------------
4068  // Temporary storage for face elements
4069  Vector<FiniteElement*> face_el_pt;
4070 
4071  // Temporary storage for the number of elements adjacent to the
4072  // boundary
4073  unsigned nele = 0;
4074 
4075  // Temporary storage for elements adjacent to the boundary that have
4076  // a common edge (related with internal boundaries)
4077  unsigned n_repeated_ele = 0;
4078 
4079  const unsigned n_regions = this->nregion();
4080 
4081  // Temporary storage for already done nodes
4082  Vector<std::pair<Node*, Node*> > done_nodes_pt;
4083 
4084  // If there is more than one region then only use boundary
4085  // coordinates from the bulk side (region 0)
4086  if (n_regions > 1)
4087  {
4088  for (unsigned rr = 0 ; rr < n_regions; rr++)
4089  {
4090  const unsigned region_id =
4091  static_cast<unsigned>(this->Region_attribute[rr]);
4092 
4093  // Loop over all elements on boundaries in region i_r
4094  const unsigned nel_in_region =
4095  this->nboundary_element_in_region(b, region_id);
4096 
4097  unsigned nel_repetead_in_region = 0;
4098 
4099  // Only bother to do anything else, if there are elements
4100  // associated with the boundary and the current region
4101  if (nel_in_region > 0)
4102  {
4103  bool repeated = false;
4104 
4105  // Loop over the bulk elements adjacent to boundary b
4106  for (unsigned e = 0; e < nel_in_region; e++)
4107  {
4108  // Get pointer to the bulk element that is adjacent to
4109  // boundary b
4110  FiniteElement* bulk_elem_pt =
4111  this->boundary_element_in_region_pt(b, region_id, e);
4112 
4113  // Remember only work with non halo elements
4114  if (bulk_elem_pt->is_halo())
4115  {
4116  n_repeated_ele++;
4117  continue;
4118  }
4119 
4120  // Find the index of the face of element e along boundary b
4121  int face_index =
4122  this->face_index_at_boundary_in_region(b,region_id,e);
4123 
4124  // Before adding the new element we need to be sure that the
4125  // edge that this element represent has not been already
4126  // added
4127  FiniteElement* tmp_ele_pt =
4128  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4129 
4130  const unsigned n_nodes = tmp_ele_pt->nnode();
4131 
4132  std::pair<Node*, Node*> tmp_pair =
4133  std::make_pair(tmp_ele_pt->node_pt(0),
4134  tmp_ele_pt->node_pt(n_nodes - 1));
4135 
4136  std::pair<Node*, Node*> tmp_pair_inverse =
4137  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4138  tmp_ele_pt->node_pt(0));
4139 
4140  // Search for repeated nodes
4141  const unsigned repeated_nodes_size = done_nodes_pt.size();
4142  for (unsigned l = 0; l < repeated_nodes_size; l++)
4143  {
4144  if (tmp_pair == done_nodes_pt[l] ||
4145  tmp_pair_inverse == done_nodes_pt[l])
4146  {
4147  nel_repetead_in_region++;
4148  repeated = true;
4149  break;
4150  }
4151  }
4152 
4153  // Create new face element
4154  if (!repeated)
4155  {
4156  // Add the pair of nodes (edge) to the node dones
4157  done_nodes_pt.push_back(tmp_pair);
4158  // Add the element to the face elements
4159  face_el_pt.push_back(tmp_ele_pt);
4160  }
4161  else
4162  {
4163  // Clean up
4164  delete tmp_ele_pt;
4165  tmp_ele_pt = 0;
4166  }
4167 
4168  // Re-start
4169  repeated = false;
4170 
4171  } // for nel
4172 
4173  nele += nel_in_region;
4174 
4175  n_repeated_ele += nel_repetead_in_region;
4176 
4177  } // if (nel_in_region > 0)
4178  } // for (rr < n_regions)
4179  } // if (n_regions > 1)
4180  //Otherwise it's just the normal boundary functions
4181  else
4182  {
4183  // Loop over all elements on boundaries
4184  nele = this->nboundary_element(b);
4185 
4186  //Only bother to do anything else, if there are elements
4187  if (nele > 0)
4188  {
4189  // Check for repeated ones
4190  bool repeated = false;
4191 
4192  // Loop over the bulk elements adjacent to boundary b
4193  for (unsigned e = 0; e < nele; e++)
4194  {
4195  // Get pointer to the bulk element that is adjacent to
4196  // boundary b
4197  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4198 
4199  // Skip the halo elements, they are not included
4200  if (bulk_elem_pt->is_halo())
4201  {
4202  n_repeated_ele++;
4203  continue;
4204  }
4205 
4206  //Find the index of the face of element e along boundary b
4207  int face_index = this->face_index_at_boundary(b, e);
4208 
4209  // Before adding the new element we need to be sure that the
4210  // edge that this element represents has not been already
4211  // added (only applies for internal boundaries)
4212  FiniteElement* tmp_ele_pt =
4213  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4214 
4215  const unsigned n_nodes = tmp_ele_pt->nnode();
4216 
4217  std::pair<Node*, Node*> tmp_pair =
4218  std::make_pair(tmp_ele_pt->node_pt(0),
4219  tmp_ele_pt->node_pt(n_nodes - 1));
4220 
4221  std::pair<Node*, Node*> tmp_pair_inverse =
4222  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4223  tmp_ele_pt->node_pt(0));
4224 
4225  // Search for repeated nodes
4226  const unsigned repeated_nodes_size = done_nodes_pt.size();
4227  for (unsigned l = 0; l < repeated_nodes_size; l++)
4228  {
4229  if (tmp_pair == done_nodes_pt[l] ||
4230  tmp_pair_inverse == done_nodes_pt[l])
4231  {
4232  // Increase the number of repeated elements
4233  n_repeated_ele++;
4234  // Mark the element as repeated
4235  repeated = true;
4236  break;
4237  }
4238  }
4239 
4240  // Create new face element
4241  if (!repeated)
4242  {
4243  // Add the pair of nodes (edge) to the node dones
4244  done_nodes_pt.push_back(tmp_pair);
4245  // Add the element to the face elements
4246  face_el_pt.push_back(tmp_ele_pt);
4247  }
4248  else
4249  {
4250  // Free the repeated bulk element!!
4251  delete tmp_ele_pt;
4252  tmp_ele_pt = 0;
4253  }
4254 
4255  // Re-start
4256  repeated = false;
4257 
4258  } // for (e < nel)
4259  } // if (nel > 0)
4260 
4261  } // else (n_regions > 1)
4262 
4263  // Do not consider the repeated elements
4264  nele-= n_repeated_ele;
4265 
4266 #ifdef PARANOID
4267  if (nele!=face_el_pt.size())
4268  {
4269  std::ostringstream error_message;
4270  error_message
4271  << "The independet counting of face elements ("<<nele<<") for "
4272  << "boundary ("<<b<<") is different\n"
4273  << "from the real number of face elements in the container ("
4274  << face_el_pt.size() <<")\n";
4275  //<< "Possible memory leak\n"
4276  throw OomphLibError(error_message.str(),
4277  OOMPH_CURRENT_FUNCTION,
4278  OOMPH_EXCEPTION_LOCATION);
4279  }
4280 #endif
4281 
4282  // ----------------------------------------------------------------
4283  // Second: Sort the face elements, only consider nonhalo elements
4284  // ----------------------------------------------------------------
4285 
4286  // Get the total number of nonhalo face elements
4287  const unsigned nnon_halo_face_elements = face_el_pt.size();
4288 
4289  // The vector of list to store the "segments" that compound the
4290  // boundary (segments may appear only in a distributed mesh)
4291  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
4292 
4293  // Number of already sorted face elements
4294  unsigned nsorted_face_elements = 0;
4295 
4296  // Keep track of who's done
4297  std::map<FiniteElement*, bool> done_el;
4298 
4299  // Keep track of which element is inverted
4300  std::map<FiniteElement*, bool> is_inverted;
4301 
4302  // Iterate until all possible segments have been created
4303  while(nsorted_face_elements < nnon_halo_face_elements)
4304  {
4305  // The ordered list of face elements (in a distributed mesh a
4306  // collection of contiguous face elements define a segment)
4307  std::list<FiniteElement*> sorted_el_pt;
4308 
4309 #ifdef PARANOID
4310  // Select an initial element for the segment
4311  bool found_initial_face_element = false;
4312 #endif
4313 
4314  FiniteElement* ele_face_pt = 0;
4315 
4316  unsigned iface = 0;
4317  for (iface = 0; iface < nele; iface++)
4318  {
4319  ele_face_pt = face_el_pt[iface];
4320  // If not done then take it as initial face element
4321  if (!done_el[ele_face_pt])
4322  {
4323 #ifdef PARANOID
4324  // Mark as found the root face element
4325  found_initial_face_element = true;
4326 #endif
4327  // Increase the number of sorted face elements
4328  nsorted_face_elements++;
4329  // Increase the counter to mark the position of the next
4330  // element number
4331  iface++;
4332  // Add the face element in the list of sorted face elements
4333  sorted_el_pt.push_back(ele_face_pt);
4334  // Mark as done
4335  done_el[ele_face_pt] = true;
4336  break;
4337  } // if (!done_el[ele_face_pt])
4338  } // for (iface < nele)
4339 
4340 #ifdef PARANOID
4341  if (!found_initial_face_element)
4342  {
4343  std::ostringstream error_message;
4344  error_message
4345  <<"Could not find an initial face element for the current segment\n";
4346  throw OomphLibError(error_message.str(),
4347  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4348  OOMPH_EXCEPTION_LOCATION);
4349  }
4350 #endif
4351 
4352  // Number of nodes
4353  const unsigned nnod = ele_face_pt->nnode();
4354 
4355  // Left and rightmost nodes (the left and right nodes of the
4356  // current face element)
4357  Node* left_node_pt = ele_face_pt->node_pt(0);
4358  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4359 
4360  // Continue iterating if a new face element has been added to the
4361  // list
4362  bool face_element_added = false;
4363 
4364  // While a new face element has been added to the set of sorted
4365  // face elements then re-iterate
4366  do
4367  {
4368  // Start from the next face element since we have already added
4369  // the previous one as the initial face element (any previous
4370  // face element had to be added on previous iterations)
4371  for (unsigned iiface = iface; iiface < nele; iiface++)
4372  {
4373  // Re-start flag
4374  face_element_added = false;
4375 
4376  // Get the candidate element
4377  ele_face_pt = face_el_pt[iiface];
4378 
4379  // Check that the candidate element has not been done and is
4380  // not a halo element
4381  if (!(done_el[ele_face_pt]))
4382  {
4383  // Get the left and right nodes of the current element
4384  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4385  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4386 
4387  // New element fits at the left of segment and is not inverted
4388  if (left_node_pt == local_right_node_pt)
4389  {
4390  left_node_pt = local_left_node_pt;
4391  sorted_el_pt.push_front(ele_face_pt);
4392  is_inverted[ele_face_pt] = false;
4393  face_element_added = true;
4394  }
4395  // New element fits at the left of segment and is inverted
4396  else if (left_node_pt == local_left_node_pt)
4397  {
4398  left_node_pt = local_right_node_pt;
4399  sorted_el_pt.push_front(ele_face_pt);
4400  is_inverted[ele_face_pt] = true;
4401  face_element_added = true;
4402  }
4403  // New element fits on the right of segment and is not inverted
4404  else if (right_node_pt == local_left_node_pt)
4405  {
4406  right_node_pt = local_right_node_pt;
4407  sorted_el_pt.push_back(ele_face_pt);
4408  is_inverted[ele_face_pt] = false;
4409  face_element_added = true;
4410  }
4411  // New element fits on the right of segment and is inverted
4412  else if (right_node_pt == local_right_node_pt)
4413  {
4414  right_node_pt = local_left_node_pt;
4415  sorted_el_pt.push_back(ele_face_pt);
4416  is_inverted[ele_face_pt] = true;
4417  face_element_added = true;
4418  }
4419 
4420  if (face_element_added)
4421  {
4422  done_el[ele_face_pt] = true;
4423  nsorted_face_elements++;
4424  break;
4425  } // if (face_element_added)
4426 
4427  } // if (!(done_el[ele_face_pt]))
4428 
4429  } // for (iiface<nnon_halo_face_element)
4430 
4431  }while(face_element_added &&
4432  (nsorted_face_elements < nnon_halo_face_elements));
4433 
4434  // Store the created segment in the vector of segments
4435  segment_sorted_ele_pt.push_back(sorted_el_pt);
4436 
4437  } // while(nsorted_face_elements < nnon_halo_face_elements);
4438 
4439  // --------------------------------------------------------------
4440  // Third: We have the face elements sorted, now assign boundary
4441  // coordinates to the nodes in the segments and compute the
4442  // arclength of the segment.
4443  // --------------------------------------------------------------
4444 
4445  // The number of segments in this processor
4446  const unsigned nsegments = segment_sorted_ele_pt.size();
4447 
4448 #ifdef PARANOID
4449  if (nnon_halo_face_elements > 0 && nsegments == 0)
4450  {
4451  std::ostringstream error_message;
4452  error_message
4453  << "The number of segments is zero, but the number of nonhalo\n"
4454  << "elements is: (" << nnon_halo_face_elements << ")\n";
4455  throw OomphLibError(error_message.str(),
4456  OOMPH_CURRENT_FUNCTION,
4457  OOMPH_EXCEPTION_LOCATION);
4458  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4459 #endif
4460 
4461  // Vector of sets that stores the nodes of each segment based on a
4462  // lexicographically order starting from the bottom left node of
4463  // each segment
4464  Vector<std::set<Node*> > segment_all_nodes_pt(nsegments);
4465 
4466  // Stores the nodes on each segment in the order they appear in the
4467  // face elements
4468  Vector<Vector<Node*> > sorted_segment_all_nodes_pt(nsegments);
4469 
4470  // Associate and arclength to each node on each segment of the
4471  // boundary, the nodes and therefore the arclength come in the same
4472  // order as the face elements
4473  Vector<Vector<double> > sorted_segment_node_arclength(nsegments);
4474 
4475  // The arclength of each segment in the current processor
4476  Vector<double> segment_arclength(nsegments);
4477 
4478  // The number of vertices of each segment
4479  Vector<unsigned> nvertices_per_segment(nsegments);
4480 
4481  // The initial zeta for the segment
4482  Vector<double> initial_zeta_segment(nsegments);
4483 
4484  // The final zeta for the segment
4485  Vector<double> final_zeta_segment(nsegments);
4486 
4487  // Go through all the segments and compute the LOCAL boundary
4488  // coordinates
4489  for (unsigned is = 0; is < nsegments; is++)
4490  {
4491 #ifdef PARANOID
4492  if (segment_sorted_ele_pt[is].size() == 0)
4493  {
4494  std::ostringstream error_message;
4495  error_message
4496  << "The (" << is << ")-th segment has no elements\n";
4497  throw OomphLibError(error_message.str(),
4498  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4499  OOMPH_EXCEPTION_LOCATION);
4500  } // if (segment_sorted_ele_pt[is].size() == 0)
4501 #endif
4502 
4503  // Get access to the first element on the segment
4504  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4505 
4506  // Number of nodes
4507  const unsigned nnod = first_ele_pt->nnode();
4508 
4509  // Get the first node of the current segment
4510  Node *first_node_pt = first_ele_pt->node_pt(0);
4511  if (is_inverted[first_ele_pt])
4512  {
4513  first_node_pt = first_ele_pt->node_pt(nnod-1);
4514  }
4515 
4516  // Coordinates of left node
4517  double x_left = first_node_pt->x(0);
4518  double y_left = first_node_pt->x(1);
4519 
4520  // Initialise boundary coordinate (local boundary coordinate for
4521  // boundaries with more than one segment)
4522  Vector<double> zeta(1, 0.0);
4523 
4524  // If we have associated a GeomObject then it is not necessary
4525  // to compute the arclength, only read the values from the nodes at
4526  // the edges
4527  if (this->boundary_geom_object_pt(b)!=0)
4528  {
4529  first_node_pt->get_coordinates_on_boundary(b, zeta);
4530  initial_zeta_segment[is] = zeta[0];
4531 
4532  // Get access to the last element on the segment
4533  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4534 
4535  // Get the last node of the current segment
4536  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
4537  if (is_inverted[last_ele_pt])
4538  {
4539  last_node_pt = last_ele_pt->node_pt(0);
4540  }
4541 
4542  last_node_pt->get_coordinates_on_boundary(b, zeta);
4543  final_zeta_segment[is] = zeta[0];
4544  }
4545 
4546  // Sort the nodes in the segment (lexicographically bottom left
4547  // node)
4548  std::set<Node*> local_nodes_pt;
4549  local_nodes_pt.insert(first_node_pt);
4550 
4551  // Associate and arclength to the sorted nodes
4552  Vector<double> sorted_node_arclength;
4553  sorted_node_arclength.push_back(0.0);
4554 
4555  // Sorts the nodes in the segments according their sorting in the
4556  // face elements
4557  Vector<Node*> sorted_nodes_pt;
4558  sorted_nodes_pt.push_back(first_node_pt);
4559 
4560  // Now loop over nodes in order
4561  for (std::list<FiniteElement*>::iterator it =
4562  segment_sorted_ele_pt[is].begin();
4563  it != segment_sorted_ele_pt[is].end(); it++)
4564  {
4565  // Get the face element
4566  FiniteElement* el_pt = *it;
4567 
4568  // Start node and increment
4569  unsigned k_nod = 1;
4570  int nod_diff = 1;
4571  if (is_inverted[el_pt])
4572  {
4573  k_nod = nnod - 2;
4574  nod_diff = -1;
4575  }
4576 
4577  // Loop over nodes
4578  for (unsigned j = 1; j < nnod; j++)
4579  {
4580  Node* nod_pt = el_pt->node_pt(k_nod);
4581  k_nod += nod_diff;
4582 
4583  // Coordinates of right node
4584  double x_right = nod_pt->x(0);
4585  double y_right = nod_pt->x(1);
4586 
4587  // Increment boundary coordinate
4588  zeta[0] += sqrt(
4589  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
4590  * (y_right - y_left));
4591 
4592  // When we have a GeomObject associated to the boundary we already
4593  // know the zeta values for the nodes, there is no need to compute
4594  // the arclength
4595  if (this->boundary_geom_object_pt(b)==0)
4596  {
4597  // Set boundary coordinate
4598 // nod_pt->set_coordinates_on_boundary(b, zeta);
4599  }
4600 
4601  // Increment reference coordinate
4602  x_left = x_right;
4603  y_left = y_right;
4604 
4605  // Get lexicographically bottom left node but only
4606  // use vertex nodes as candidates
4607  local_nodes_pt.insert(nod_pt);
4608 
4609  // Associate the arclength for the current node
4610  sorted_node_arclength.push_back(zeta[0]);
4611 
4612  // Store the node in the sorted nodes storage
4613  sorted_nodes_pt.push_back(nod_pt);
4614 
4615  } // for (j < nnod)
4616 
4617  } // iterator over the elements in the segment
4618 
4619  // Info. to be passed to the other processors
4620  // The initial arclength for the segment that goes after this depends
4621  // on the current segment arclength
4622  segment_arclength[is] = zeta[0];
4623 
4624  // Info. to be passed to the other processors
4625  // The initial vertex number for the segment that goes after this
4626  // depends on the current sement vertices number
4627  nvertices_per_segment[is] = local_nodes_pt.size();
4628 
4629  // Add the nodes for the corresponding segment in the container
4630  segment_all_nodes_pt[is] = local_nodes_pt;
4631 
4632  // Add the arclengths to the nodes in the segment
4633  sorted_segment_node_arclength[is] = sorted_node_arclength;
4634 
4635  // Add the sorted nodes to the storage
4636  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4637 
4638  // The attaching of the halo elements at both sides of the segments is
4639  // performed only if segments connectivity needs to be computed
4640 
4641  } // for (is < nsegments)
4642 
4643  // ------------------------------------------------------------------
4644  // Fourth: Now we have the segments sorted, with arclength and with
4645  // LOCAL boundary coordinates assigned to the nodes. Identify the
4646  // nodes on the segments with the input segments and re-assign all
4647  // the info. related with the identification of segments
4648  // ------------------------------------------------------------------
4649 
4650  // Get the number of segments for the old sorted segments
4651  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4652 
4653  // ------------------------------------------------------------------
4654  // Copy the old info. in temporary storages
4655  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4656 
4657  Vector<Vector<double> >
4658  old_boundary_segment_initial_coordinate(old_nsegments);
4659  Vector<Vector<double> >
4660  old_boundary_segment_final_coordinate(old_nsegments);
4661 
4662  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4663  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4664 
4665  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4666  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4667 
4668  // Back-up the information
4669  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4670  {
4671  old_boundary_segment_inverted[old_is] =
4672  boundary_segment_inverted(b)[old_is];
4673 
4674  old_boundary_segment_initial_coordinate[old_is].resize(2);
4675  old_boundary_segment_final_coordinate[old_is].resize(2);
4676  for (unsigned i = 0; i < 2; i++)
4677  {
4678  old_boundary_segment_initial_coordinate[old_is][i] =
4679  boundary_segment_initial_coordinate(b)[old_is][i];
4680 
4681  old_boundary_segment_final_coordinate[old_is][i] =
4682  boundary_segment_final_coordinate(b)[old_is][i];
4683  }
4684 
4685  // Check if the boundary has an associated GeomObject
4686  if (this->boundary_geom_object_pt(b)!=0)
4687  {
4688  old_boundary_segment_initial_zeta[old_is] =
4689  boundary_segment_initial_zeta(b)[old_is];
4690 
4691  old_boundary_segment_final_zeta[old_is] =
4692  boundary_segment_final_zeta(b)[old_is];
4693 
4694  } // if (this->boundary_geom_object_pt(b)!=0)
4695  else
4696  {
4697  old_boundary_segment_initial_arclength[old_is] =
4698  boundary_segment_initial_arclength(b)[old_is];
4699 
4700  old_boundary_segment_final_arclength[old_is] =
4701  boundary_segment_final_arclength(b)[old_is];
4702 
4703  } // else if (this->boundary_geom_object_pt(b)!=0)
4704 
4705  } // for (old_is < old_nsegments)
4706 
4707  // ------------------------------------------------------------------
4708  // Now clear the original storages
4709  Boundary_segment_inverted[b].clear();
4710  Boundary_segment_initial_coordinate[b].clear();
4711  Boundary_segment_final_coordinate[b].clear();
4712 
4713  Boundary_segment_initial_zeta[b].clear();
4714  Boundary_segment_final_zeta[b].clear();
4715 
4716  Boundary_segment_initial_arclength[b].clear();
4717  Boundary_segment_final_arclength[b].clear();
4718  // ------------------------------------------------------------------
4719  // .. and resize the storages for the new number of segments
4720  Boundary_segment_inverted[b].resize(nsegments);
4721  Boundary_segment_initial_coordinate[b].resize(nsegments);
4722  Boundary_segment_final_coordinate[b].resize(nsegments);
4723 
4724  // Check if the boundary has an associated GeomObject
4725  if (this->boundary_geom_object_pt(b)!=0)
4726  {
4727  Boundary_segment_initial_zeta[b].resize(nsegments);
4728  Boundary_segment_final_zeta[b].resize(nsegments);
4729  }
4730  else
4731  {
4732  Boundary_segment_initial_arclength[b].resize(nsegments);
4733  Boundary_segment_final_arclength[b].resize(nsegments);
4734  }
4735  // ------------------------------------------------------------------
4736  // map to know if the new segment has been re-assigned the info.
4737  std::map<unsigned, bool> done_segment;
4738 
4739  // Count the number of re-assigned segments with the new values
4740  unsigned re_assigned_segments = 0;
4741 
4742  // Go through all the old segments (the input segments)
4743  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4744  {
4745  // Get the first and last zeta values for the current segment
4746  const double old_initial_arclength =
4747  old_boundary_segment_initial_arclength[old_is];
4748  const double old_final_arclength =
4749  old_boundary_segment_final_arclength[old_is];
4750  // Get the "is inverted" segment information
4751  const unsigned old_inverted_segment =
4752  old_boundary_segment_inverted[old_is];
4753 
4754  // Check if the boundary coordinates in the segment go in
4755  // increasing or decreasing order
4756  bool old_increasing_order = false;
4757  if (old_initial_arclength < old_final_arclength)
4758  {old_increasing_order = true;}
4759 
4760  // Now get the first and last node of the current segment
4761  // Get the first element
4762  FiniteElement* first_old_seg_ele_pt =
4763  old_segment_sorted_ele_pt[old_is].front();
4764 
4765  // Number of nodes
4766  const unsigned nnod = first_old_seg_ele_pt->nnode();
4767 
4768  // Get the first node of the current segment
4769  Node *first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4770  if (old_is_inverted[first_old_seg_ele_pt])
4771  {
4772  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod-1);
4773  }
4774 
4775  // Get access to the last element on the segment
4776  FiniteElement* last_old_seg_ele_pt =
4777  old_segment_sorted_ele_pt[old_is].back();
4778 
4779  // Get the last node of the current segment
4780  Node *last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod-1);
4781  if (old_is_inverted[last_old_seg_ele_pt])
4782  {
4783  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4784  }
4785  // Check if the segment is inverted, if that is the case then
4786  // also invert the nodes
4787  if (old_inverted_segment)
4788  {
4789  Node* temp_node_pt = first_old_seg_node_pt;
4790  first_old_seg_node_pt = last_old_seg_node_pt;
4791  last_old_seg_node_pt = temp_node_pt;
4792  }
4793 
4794  // We have the first and last node of the old segment (input
4795  // segment), now identify in which segment, of those with only
4796  // nonhalo face elements, they are
4797  for (unsigned is = 0; is < nsegments; is++)
4798  {
4799  if (!done_segment[is])
4800  {
4801  // Go through the nodes of the current segment and try to find
4802  // the old nodes
4803  bool found_first_old_seg_node = false;
4804  bool found_last_old_seg_node = false;
4805  bool same_order = false;
4806 
4807  // Get the first node of the current segment
4808  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4809  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4810  if (is_inverted[first_seg_ele_pt])
4811  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
4812 
4813  // Get the arclength for the first node
4814  const double segment_first_node_zeta =
4815  sorted_segment_node_arclength[is][0];
4816 
4817  // Get the node coordinates for the first node
4818  Vector<double> first_node_coord(2);
4819  for (unsigned i = 0; i < 2; i++)
4820  {first_node_coord[i] = first_seg_node_pt->x(i);}
4821 
4822  // Get the last node of the current segment
4823  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4824  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
4825  if (is_inverted[last_seg_ele_pt])
4826  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
4827 
4828  // Get the arclength for the last node
4829  const double segment_final_node_zeta = segment_arclength[is];
4830 
4831  // Get the node coordinates for the last node
4832  Vector<double> last_node_coord(2);
4833  for (unsigned i = 0; i < 2; i++)
4834  {last_node_coord[i] = last_seg_node_pt->x(i);}
4835 
4836  // Temporary storage for the nodes of the current segment
4837  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4838  // Get the number of nodes in the segment
4839  const unsigned nsegment_node = segment_node_pt.size();
4840  for (unsigned in = 0; in < nsegment_node; in++)
4841  {
4842  Node* current_node_pt = segment_node_pt[in];
4843  if (!found_first_old_seg_node &&
4844  first_old_seg_node_pt == current_node_pt)
4845  {
4846  // Get the arclength assigned to the node on the old
4847  // segment
4848  const double current_node_zeta =
4849  sorted_segment_node_arclength[is][in];
4850 
4851  // Now check if the new segment has the same orientation
4852  // as the old one
4853  if (!found_last_old_seg_node) // has the same orientation
4854  {
4855  // Re-assign the first node coordinates
4856  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4857 
4858  // Check if the boundary has an associated GeomObject
4859  if (this->boundary_geom_object_pt(b)!=0)
4860  {
4861  // Assign the zeta values if the current segment has the
4862  // nodes of the old one
4863 
4864  // If we are in the same order then pass the values as
4865  // they are
4866  Boundary_segment_initial_zeta[b][is] =
4867  initial_zeta_segment[is];
4868 
4869  } // if (this->boundary_geom_object_pt(b)!=0)
4870  else
4871  {
4872  // Get the distance to the first node
4873  const double distance =
4874  std::fabs(current_node_zeta - segment_first_node_zeta);
4875 
4876  double new_initial_arclength = old_initial_arclength;
4877 
4878  // Now check if the zeta values are in increasing order
4879  if (old_increasing_order)
4880  {
4881  // Substract the distance
4882  new_initial_arclength-= distance;
4883  }
4884  else
4885  {
4886  // Add the distance
4887  new_initial_arclength+= distance;
4888  }
4889 
4890  // Re-assign the initial arclength for the current segment
4891  Boundary_segment_initial_arclength[b][is] =
4892  new_initial_arclength;
4893 
4894  } // else if (this->boundary_geom_object_pt(b)!=0)
4895  } // if (!found_last_old_seg_node)
4896  else // has different orientation
4897  {
4898  // Re-assign the first node coordinates
4899  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4900 
4901  // Check if the boundary has an associated GeomObject
4902  if (this->boundary_geom_object_pt(b)!=0)
4903  {
4904  // Assign the zeta values if the current segment has the
4905  // nodes of the old one
4906 
4907  // Not the same order, we need to copy the zeta values
4908  // from the other end, the inverted flag is changed at
4909  // the end. Copy the value from the final end
4910  Boundary_segment_initial_zeta[b][is] =
4911  final_zeta_segment[is];
4912 
4913  } // if (this->boundary_geom_object_pt(b)!=0)
4914  else
4915  {
4916  // Get the distance to the final node
4917  const double distance =
4918  std::fabs(current_node_zeta - segment_final_node_zeta);
4919 
4920  double new_initial_arclength = old_initial_arclength;
4921 
4922  // Now check if the zeta values are in increasing order
4923  if (old_increasing_order)
4924  {
4925  // Substract the distance
4926  new_initial_arclength-= distance;
4927  }
4928  else
4929  {
4930  // Add the distance
4931  new_initial_arclength+= distance;
4932  }
4933 
4934  // Re-assign the initial arclength for the current segment
4935  Boundary_segment_initial_arclength[b][is] =
4936  new_initial_arclength;
4937 
4938  } // else if (this->boundary_geom_object_pt(b)!=0)
4939  } // else if (!found_last_old_seg_node)
4940 
4941  // Mark as found the first node
4942  found_first_old_seg_node = true;
4943 
4944  }
4945  // if (!found_first_old_seg_node &&
4946  // first_old_seg_node_pt == current_node_pt)
4947 
4948  // If we found first the first node then the segments have
4949  // the same order
4950  if (found_first_old_seg_node && !found_last_old_seg_node)
4951  {same_order = true;}
4952 
4953  if (!found_last_old_seg_node &&
4954  last_old_seg_node_pt == current_node_pt)
4955  {
4956  // Get the boundary coordinates assigned to the node on
4957  // the old segment
4958  const double current_node_zeta =
4959  sorted_segment_node_arclength[is][in];
4960 
4961  // Now check if the new segment has the same orientation
4962  // as the old one
4963  if (found_first_old_seg_node) // has the same orientation
4964  {
4965  // Re-assign the last node coordinates
4966  Boundary_segment_final_coordinate[b][is] = last_node_coord;
4967 
4968  // Check if the boundary has an associated GeomObject
4969  if (this->boundary_geom_object_pt(b)!=0)
4970  {
4971  // Assign the zeta values if the current segment has the
4972  // nodes of the old one
4973 
4974  // If we are in the same order then pass the values as
4975  // they are
4976  Boundary_segment_final_zeta[b][is] =
4977  final_zeta_segment[is];
4978 
4979  } // if (this->boundary_geom_object_pt(b)!=0)
4980  else
4981  {
4982  // Get the distance to the last node
4983  const double distance =
4984  std::fabs(current_node_zeta - segment_final_node_zeta);
4985 
4986  double new_final_arclength = old_final_arclength;
4987 
4988  // Now check if the zeta values are in increasing order
4989  if (old_increasing_order)
4990  {
4991  // Add the distance
4992  new_final_arclength+= distance;
4993  }
4994  else
4995  {
4996  // Substract the distance
4997  new_final_arclength-= distance;
4998  }
4999 
5000  // Re-assign the final arclength for the current segment
5001  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5002 
5003  } // else if (this->boundary_geom_object_pt(b)!=0)
5004  } // if (found_first_old_seg_node)
5005  else
5006  {
5007  // Re-assign the last node coordinates
5008  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5009 
5010  // Check if the boundary has an associated GeomObject
5011  if (this->boundary_geom_object_pt(b)!=0)
5012  {
5013  // Assign the zeta values if the current segment has the
5014  // nodes of the old one
5015 
5016  // Not the same order, we need to copy the zeta values
5017  // from the other end, the inverted flag is changed at
5018  // the end. Copy the value from the initial end
5019  Boundary_segment_final_zeta[b][is] =
5020  initial_zeta_segment[is];
5021 
5022  } // if (this->boundary_geom_object_pt(b)!=0)
5023  else
5024  {
5025  // Get the distance to the last node
5026  const double distance =
5027  std::fabs(current_node_zeta - segment_first_node_zeta);
5028 
5029  double new_final_arclength = old_final_arclength;
5030 
5031  // Now check if the zeta values are in increasing order
5032  if (old_increasing_order)
5033  {
5034  // Add the distance
5035  new_final_arclength+= distance;
5036  }
5037  else
5038  {
5039  // Substract the distance
5040  new_final_arclength-= distance;
5041  }
5042 
5043  // Re-assign the final arclength for the current segment
5044  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5045 
5046  } // else if (this->boundary_geom_object_pt(b)!=0)
5047  } // if (found_first_old_seg_node)
5048 
5049  // Mark as found the last node
5050  found_last_old_seg_node = true;
5051 
5052  } // if (!found_last_old_seg_node &&
5053  // last_old_seg_node_pt == current_node_pt)
5054 
5055  // If we found the last node first then the segments have
5056  // not the same order
5057  if (!found_first_old_seg_node && found_last_old_seg_node)
5058  {same_order = false;}
5059 
5060  if (found_first_old_seg_node && found_last_old_seg_node)
5061  {
5062  // Check if necessary to change the information that
5063  // states if a segment is inverted or not
5064  if (same_order)
5065  {Boundary_segment_inverted[b][is] = old_inverted_segment;}
5066  else
5067  {Boundary_segment_inverted[b][is] = !old_inverted_segment;}
5068 
5069  // Mark the segment as done
5070  done_segment[is] = true;
5071 
5072  // Increase the number of re-assigned segments
5073  re_assigned_segments++;
5074 
5075  // Break the for that look for the nodes in the segments
5076  break;
5077  }
5078 
5079  } // for (in < nsegment_node)
5080 
5081 #ifdef PARANOID
5082  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5083  (!found_first_old_seg_node && found_last_old_seg_node))
5084  {
5085  std::stringstream error_message;
5086  error_message
5087  << "Working with boundary ("<< b << ").\nOnly the first node or "
5088  << "the last node of the old segment (" << old_is << ") was\n"
5089  << "found. Both, first and last node should have been found in "
5090  << "the same segment!!!.\n"
5091  << "Found first seg node:" << found_first_old_seg_node << "\n"
5092  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5093  throw OomphLibError(error_message.str(),
5094  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5095  OOMPH_EXCEPTION_LOCATION);
5096  }
5097 #endif
5098 
5099  } // if (!done_segment[is])
5100  } // for (is < nsegments)
5101  } // for (old_is < old_nsegments)
5102 
5103  // For those segments not identified set dummy values, the boundary
5104  // coordinates should be corrected at the synchronisation stage
5105 
5106  // loop over the new segments and check if there not identified
5107  // segments
5108  for (unsigned is = 0; is < nsegments; is++)
5109  {
5110  // Was the segment identified
5111  if (!done_segment[is])
5112  {
5113  // Get the first node of the current segment
5114  FiniteElement* first_seg_ele_pt =
5115  segment_sorted_ele_pt[is].front();
5116  // Number of nodes
5117  const unsigned nnod = first_seg_ele_pt->nnode();
5118 
5119  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5120  if (is_inverted[first_seg_ele_pt])
5121  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
5122 
5123  // Get the arclength for the first node
5124  const double segment_first_node_zeta =
5125  sorted_segment_node_arclength[is][0];
5126 
5127  // Get the node coordinates for the first node
5128  Vector<double> first_node_coord(2);
5129  for (unsigned i = 0; i < 2; i++)
5130  {first_node_coord[i] = first_seg_node_pt->x(i);}
5131 
5132  // Get the last node of the current segment
5133  FiniteElement* last_seg_ele_pt =
5134  segment_sorted_ele_pt[is].back();
5135  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
5136  if (is_inverted[last_seg_ele_pt])
5137  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
5138 
5139  // Get the arclength for the last node
5140  const double segment_final_node_zeta = segment_arclength[is];
5141 
5142  // Get the node coordinates for the last node
5143  Vector<double> last_node_coord(2);
5144  for (unsigned i = 0; i < 2; i++)
5145  {last_node_coord[i] = last_seg_node_pt->x(i);}
5146 
5147  // Re-assign the initial node coordinates
5148  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5149 
5150  // Check if the boundary has an associated GeomObject
5151  if (this->boundary_geom_object_pt(b)!=0)
5152  {
5153  // Assign the zeta values if the current segment has the
5154  // nodes of the old one
5155 
5156  // If we are in the same order then pass the values as
5157  // they are
5158  Boundary_segment_initial_zeta[b][is] =
5159  initial_zeta_segment[is];
5160 
5161  } // if (this->boundary_geom_object_pt(b)!=0)
5162  else
5163  {
5164  // Re-assign the initial arclength for the current segment
5165  Boundary_segment_initial_arclength[b][is] =
5166  segment_first_node_zeta;
5167 
5168  } // else if (this->boundary_geom_object_pt(b)!=0)
5169 
5170  // Re-assign the initial node coordinates
5171  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5172 
5173  // Check if the boundary has an associated GeomObject
5174  if (this->boundary_geom_object_pt(b)!=0)
5175  {
5176  // Assign the zeta values if the current segment has the
5177  // nodes of the old one
5178 
5179  // If we are in the same order then pass the values as
5180  // they are
5181  Boundary_segment_final_zeta[b][is] =
5182  final_zeta_segment[is];
5183 
5184  } // if (this->boundary_geom_object_pt(b)!=0)
5185  else
5186  {
5187  // Re-assign the final arclength for the current segment
5188  Boundary_segment_final_arclength[b][is] =
5189  segment_final_node_zeta;
5190 
5191  } // else if (this->boundary_geom_object_pt(b)!=0)
5192 
5193  Boundary_segment_inverted[b][is] = 0;
5194 
5195  // Mark the segment as done
5196  done_segment[is] = true;
5197 
5198  // Increase the number of re-assigned segments
5199  re_assigned_segments++;
5200 
5201  } // if (!done_segment[is])
5202 
5203  } // for (is < nsegments)
5204 
5205 #ifdef PARANOID
5206  // Compare the number of new segments identified with the old segments
5207  if (re_assigned_segments != nsegments)
5208  {
5209  std::stringstream error_message;
5210  error_message
5211  << "Working with boundary ("<< b << ").\nThe number of re-assigned "
5212  << "segments (" << re_assigned_segments
5213  << ") is different from the number\nof segments ("<< nsegments
5214  << ")\n\n";
5215  throw OomphLibError(error_message.str(),
5216  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5217  OOMPH_EXCEPTION_LOCATION);
5218  } // if (re_assigned_segments != nsegments)
5219 #endif
5220 
5221  // Clean all the created face elements
5222  for (unsigned i = 0; i < nele; i++)
5223  {
5224  delete face_el_pt[i];
5225  face_el_pt[i] = 0;
5226  }
5227 
5228  }
5229 
5230  ///=====================================================================
5231  /// Select face elements from a given boundary. In case the we are
5232  /// dealing with an internal boundary we use a set of criterias to
5233  /// decide which of the two face elements should be used on represent
5234  /// the internal boundary. We return the face elements, halo or
5235  /// haloed on this processor that form the boundary. The caller method
5236  /// should be in charge of selecting nonhalo elements and deleting the face
5237  /// elements created by this method
5238  /// =====================================================================
5239  template <class ELEMENT>
5241  select_boundary_face_elements(Vector<FiniteElement*> &face_ele_pt,
5242  const unsigned &b,
5243  bool &is_internal_boundary,
5244  std::map<FiniteElement*,FiniteElement*>
5245  &face_to_bulk_element_pt)
5246  {
5247  // Get the communicator of the mesh
5248  OomphCommunicator* comm_pt = this->communicator_pt();
5249 
5250  const unsigned my_rank = comm_pt->my_rank();
5251 
5252  // ------------------------------------------------------------------
5253  // 1) Get the face elements associated with the current boundary
5254  // ------------------------------------------------------------------
5255 
5256  // Temporary storage for face elements (do not take care of
5257  // repeated face elements)
5258  Vector<FiniteElement*> tmp_face_ele_pt;
5259 
5260  const unsigned nregions = this->nregion();
5261 
5262  // If there is more than one region then only use boundary
5263  // coordinates from the bulk side (region 0)
5264  if (nregions > 1)
5265  {
5266  for (unsigned ir = 0 ; ir < nregions; ir++)
5267  {
5268  const unsigned region_id =
5269  static_cast<unsigned>(this->Region_attribute[ir]);
5270 
5271  // Loop over all elements on boundaries in region -ir-
5272  const unsigned nele_in_region =
5273  this->nboundary_element_in_region(b, region_id);
5274 
5275  // Only bother to do anything else, if there are elements
5276  // associated with the boundary and the current region
5277  if (nele_in_region > 0)
5278  {
5279  // Loop over the bulk elements adjacent to boundary b
5280  for (unsigned e = 0; e < nele_in_region; e++)
5281  {
5282  // Get pointer to the bulk element that is adjacent
5283  // to boundary b
5284  FiniteElement* bulk_ele_pt =
5285  this->boundary_element_in_region_pt(b, region_id, e);
5286 
5287  // Get the index of the face of element e along
5288  // boundary b
5289  int face_index =
5290  this->face_index_at_boundary_in_region(b,region_id,e);
5291 
5292  // Create the face element
5293  FiniteElement* tmp_face_el_pt =
5294  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5295 
5296  // Associated the face element with the bulk
5297  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5298 
5299  // ... and add it to the tmp storage for all the
5300  // face elements, do not take care for repeated
5301  // ones (at the moment)
5302  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5303 
5304  } // for (e < nele_in_region)
5305 
5306  } // if (nele_in_region > 0)
5307 
5308  } // for (ir < n_regions)
5309 
5310  } // if (n_regions > 1)
5311 
5312  //Otherwise it's just the normal boundary functions
5313  else
5314  {
5315  // Loop over all elements on boundaries
5316  const unsigned nbound_ele = this->nboundary_element(b);
5317 
5318  //Only bother to do anything else, if there are elements
5319  if (nbound_ele > 0)
5320  {
5321  // Loop over the bulk elements adjacent to boundary b
5322  for (unsigned e = 0; e < nbound_ele; e++)
5323  {
5324  // Get pointer to the bulk element that is adjacent to
5325  // boundary b
5326  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5327 
5328  // Get the index of the face of element e along
5329  // boundary b
5330  int face_index = this->face_index_at_boundary(b, e);
5331 
5332  // Create the face element
5333  FiniteElement* tmp_face_el_pt =
5334  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5335 
5336  // Associated the face element with the bulk
5337  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5338 
5339  // ... and add it to the tmp storage for all the face
5340  // elements, do not care for repeated ones (at the
5341  // moment)
5342  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5343 
5344  } // (e < nbound_ele)
5345 
5346  } // (nbound_ele > 0)
5347 
5348  } // else (n_regions > 1)
5349 
5350  // map to know which face element has been already done
5351  std::map<FiniteElement*,bool> done_face;
5352 
5353  // Set the flag to indicate if we are working with an internal
5354  // boundary
5355  is_internal_boundary = false;
5356 
5357  // Free the memory of the elements in this container (only used
5358  // when working with internal boundaries)
5359  Vector<FiniteElement*> free_memory_face_ele_pt;
5360 
5361  // Get the number of face elements in the boundary (including
5362  // repeated)
5363  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5364  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5365  {
5366  // Get the possible main element
5367  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5368  if (!done_face[main_face_ele_pt])
5369  {
5370  // Mark the face element as done
5371  done_face[main_face_ele_pt] = true;
5372  // Get the number of nodes for the face element
5373  const unsigned nnodes = main_face_ele_pt->nnode();
5374  // Get the first and last node of the main face element
5375  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5376  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5377  // Look for the other side face element (we can start from
5378  // the next one, all previous face elements have been
5379  // already identified with its other side face)
5380  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5381  {
5382  // Get the possible dependant element
5383  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5384  if (!done_face[dependant_face_ele_pt])
5385  {
5386  // Get the first and last node of the dependant
5387  // face element
5388  Node* dependant_first_node_pt =
5389  dependant_face_ele_pt->node_pt(0);
5390  Node* dependant_last_node_pt =
5391  dependant_face_ele_pt->node_pt(nnodes-1);
5392  // Check if the nodes at the ends of both face
5393  // elements match (also check the reversed case)
5394  if (((dependant_first_node_pt == main_first_node_pt) &&
5395  (dependant_last_node_pt == main_last_node_pt)) ||
5396  ((dependant_first_node_pt == main_last_node_pt) &&
5397  (dependant_last_node_pt == main_first_node_pt)))
5398  {
5399  // Set the flag to indicate we are working with an
5400  // internal boundary
5401  is_internal_boundary = true;
5402  // Mark the face element as done
5403  done_face[dependant_face_ele_pt] = true;
5404 
5405  // Now choose which face element will be used
5406  // as the main element. We get the processor in
5407  // charge of the element and choose the one
5408  // with the highest processor in charge or the
5409  // bottom-left bulk element in case the both
5410  // faces are on the same processor
5411 
5412  // Get the bulk element for each face element
5413  // (the main and the dependant face element)
5414  FiniteElement *main_bulk_ele_pt =
5415  face_to_bulk_element_pt[main_face_ele_pt];
5416  FiniteElement *dependant_bulk_ele_pt =
5417  face_to_bulk_element_pt[dependant_face_ele_pt];
5418 
5419  // Get the processor in charge for each bulk
5420  // element
5421  int processor_in_charge_main_bulk_ele =
5422  main_bulk_ele_pt->non_halo_proc_ID();
5423  int processor_in_charge_dependant_bulk_ele =
5424  dependant_bulk_ele_pt->non_halo_proc_ID();
5425 
5426  // If the processor in charge is negative the
5427  // element is not halo, therefore the processor
5428  // in charge is the current one
5429  if (processor_in_charge_main_bulk_ele < 0)
5430  {
5431  processor_in_charge_main_bulk_ele=
5432  static_cast<int>(my_rank);
5433  }
5434  if (processor_in_charge_dependant_bulk_ele < 0)
5435  {
5436  processor_in_charge_dependant_bulk_ele=
5437  static_cast<int>(my_rank);
5438  }
5439 
5440  // Flag to know if add the main or dependant
5441  // face element
5442  bool add_main_face_element = true;
5443  if (processor_in_charge_dependant_bulk_ele >
5444  processor_in_charge_main_bulk_ele)
5445  {
5446  // Include the dependant element
5447  add_main_face_element = false;
5448  }
5449  else if (processor_in_charge_main_bulk_ele ==
5450  processor_in_charge_dependant_bulk_ele)
5451  {
5452  // When the processor in charge for both
5453  // elements is the same then use the
5454  // bottom-left criteria on the bulk
5455  // elements to choose the main face element
5456  Vector<double> main_ele_coordinates(2);
5457  Vector<double> dependant_ele_coordinates(2);
5458  // Get the number of nodes on the bulk
5459  // elements
5460  const unsigned n_bulk_nodes =
5461  main_bulk_ele_pt->nnode();
5462  for (unsigned inode = 0; inode < n_bulk_nodes;
5463  inode++)
5464  {
5465  for (unsigned idim = 0; idim < 2; idim++)
5466  {
5467  main_ele_coordinates[idim]+=
5468  main_bulk_ele_pt->node_pt(inode)->
5469  x(idim);
5470  dependant_ele_coordinates[idim]+=
5471  dependant_bulk_ele_pt->node_pt(inode)->
5472  x(idim);
5473  } // (idim < 2)
5474 
5475  } // (inode < n_bulk_nodes)
5476 
5477  // Get the average of the nodes coordinates
5478  for (unsigned idim = 0; idim < 2; idim++)
5479  {
5480  main_ele_coordinates[idim]/=
5481  (double)n_bulk_nodes;
5482  dependant_ele_coordinates[idim]/=
5483  (double)n_bulk_nodes;
5484  }
5485 
5486  // Once we know the average coordinates for
5487  // each element then we choose the one with
5488  // the bottom-left averaged coordinates
5489  if (dependant_ele_coordinates[1] <
5490  main_ele_coordinates[1])
5491  {add_main_face_element = false;}
5492  else if(dependant_ele_coordinates[1]==
5493  main_ele_coordinates[1])
5494  {
5495  // The left-most element
5496  if(dependant_ele_coordinates[0] <
5497  main_ele_coordinates[0])
5498  {add_main_face_element = false;}
5499  }
5500  } // else -- The processor in charge is the
5501  // same for both elements
5502 
5503  if (add_main_face_element)
5504  {
5505  // Add the main face element to the storage
5506  // so we get the halo and haloed nodes from
5507  // it
5508  face_ele_pt.push_back(main_face_ele_pt);
5509  // Mark the dependat face element to free
5510  // its memory
5511  free_memory_face_ele_pt.
5512  push_back(dependant_face_ele_pt);
5513  }
5514  else
5515  {
5516  // Add the dependant face element to the
5517  // storage so we get the halo and haloed
5518  // nodes from it
5519  face_ele_pt.push_back(dependant_face_ele_pt);
5520  // Mark the main face element to free its
5521  // memory
5522  free_memory_face_ele_pt.
5523  push_back(main_face_ele_pt);
5524  }
5525 
5526  // Break the for to look for the next face
5527  // element
5528  break;
5529 
5530  } // if -- matching of nodes from main ele and
5531  // dependant ele
5532 
5533  } // if (!done_face[dependant_face_ele_pt])
5534 
5535  } // for (iie < n_tmp_face_ele)
5536 
5537  } // if (!done_face[main_face_ele_pt])
5538 
5539  } // for (ie < n_tmp_face_ele)
5540 
5541  // Are there any face element to free its memory
5542  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5543  if (n_free_face_ele == 0)
5544  {
5545  // If there is not face elements to free memory that means that
5546  // we are not working with an internal boundary, therefore copy
5547  // all the element from the tmp face elements into the face
5548  // elements container
5549 
5550  // Resize the container
5551  face_ele_pt.resize(n_tmp_face_ele);
5552  // loop over the elements and copy them
5553  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5554  {
5555  face_ele_pt[i] = tmp_face_ele_pt[i];
5556  } // for (i < n_tmp_face_ele)
5557 
5558  } // if (n_free_face_ele == 0)
5559  else
5560  {
5561  // ... otherwise free the memory of the indicated elements
5562  // loop over the elements to free its memory
5563  for (unsigned i = 0; i < n_free_face_ele; i++)
5564  {
5565  delete free_memory_face_ele_pt[i];
5566  free_memory_face_ele_pt[i] = 0;
5567  } // for (i < n_free_face_ele)
5568  }
5569 
5570  }
5571 
5572  ///========================================================================
5573  /// In charge of sinchronize the boundary coordinates for internal
5574  /// boundaries that were split as part of the distribution
5575  /// process. Called after setup_boundary_coordinates() for the
5576  /// original mesh only
5577  ///========================================================================
5578  template <class ELEMENT>
5581  {
5582  // ------------------------------------------------------------------
5583  // First: Get the face elements associated with the current boundary
5584  // ------------------------------------------------------------------
5585 
5586  // Get the communicator of the mesh
5587  OomphCommunicator* comm_pt = this->communicator_pt();
5588 
5589  const unsigned nproc = comm_pt->nproc();
5590  const unsigned my_rank = comm_pt->my_rank();
5591 
5592  // Temporary storage for face elements (do not take care of repeated
5593  // face elements)
5594  Vector<FiniteElement*> tmp_face_ele_pt;
5595 
5596  const unsigned nregions = this->nregion();
5597 
5598  // map to associate the face element to the bulk element, necessary
5599  // to get the processor in charge for the halo elements
5600  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
5601 
5602  // If there is more than one region then only use boundary
5603  // coordinates from the bulk side (region 0)
5604  if (nregions > 1)
5605  {
5606  for (unsigned ir = 0 ; ir < nregions; ir++)
5607  {
5608  const unsigned region_id =
5609  static_cast<unsigned>(this->Region_attribute[ir]);
5610 
5611  // Loop over all elements on boundaries in region -ir-
5612  const unsigned nele_in_region =
5613  this->nboundary_element_in_region(b, region_id);
5614 
5615  // Only bother to do anything else, if there are elements
5616  // associated with the boundary and the current region
5617  if (nele_in_region > 0)
5618  {
5619  // Loop over the bulk elements adjacent to boundary b
5620  for (unsigned e = 0; e < nele_in_region; e++)
5621  {
5622  // Get pointer to the bulk element that is adjacent to boundary b
5623  FiniteElement* bulk_ele_pt =
5624  this->boundary_element_in_region_pt(b, region_id, e);
5625 
5626  // Get the index of the face of element e along boundary b
5627  int face_index=this->face_index_at_boundary_in_region(b,region_id,e);
5628 
5629  // Create the face element
5630  FiniteElement* tmp_face_el_pt =
5631  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5632 
5633  // ... and add it to the tmp storage for all the face
5634  // elements, do not take care for repeated ones (at the
5635  // moment)
5636  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5637  // Create the map to know if the element is halo
5638  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5639 
5640  } // for (e < nele_in_region)
5641 
5642  } // if (nele_in_region > 0)
5643 
5644  } // for (ir < n_regions)
5645 
5646  } // if (n_regions > 1)
5647 
5648  //Otherwise it's just the normal boundary functions
5649  else
5650  {
5651  // Loop over all elements on boundaries
5652  const unsigned nbound_ele = this->nboundary_element(b);
5653 
5654  //Only bother to do anything else, if there are elements
5655  if (nbound_ele > 0)
5656  {
5657  // Loop over the bulk elements adjacent to boundary b
5658  for (unsigned e = 0; e < nbound_ele; e++)
5659  {
5660  // Get pointer to the bulk element that is adjacent to boundary b
5661  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5662 
5663  // Get the index of the face of element e along boundary b
5664  int face_index = this->face_index_at_boundary(b, e);
5665 
5666  // Create the face element
5667  FiniteElement* tmp_face_el_pt =
5668  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5669 
5670  // ... and add it to the tmp storage for all the face
5671  // elements, do not care for repeated ones (at the moment)
5672  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5673  // Create the map to know if the element is halo
5674  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5675 
5676  } // (e < nbound_ele)
5677 
5678  } // (nbound_ele > 0)
5679 
5680  } // else (n_regions > 1)
5681 
5682  // Temporary storage for one side face elements. In case we are
5683  // working with an internal boundary here we store only one of the
5684  // face elements that are at each side of the boundary
5685  Vector<FiniteElement*> face_ele_pt;
5686 
5687  // map to know which face element has been already done
5688  std::map<FiniteElement*,bool> done_face;
5689 
5690  // Flag to indicate if we are working with an internal boundary
5691  bool is_internal_boundary = false;
5692 
5693 #ifdef PARANOID
5694  // Flag to indicate if we are working with an internal boundary (paranoid)
5695  bool is_internal_boundary_paranoid = false;
5696 
5697  // Count the number of other side face elements found in case we are
5698  // working with an internal boundary
5699  unsigned nfound_face_elements = 0;
5700 #endif
5701 
5702  // Get the number of face elements in the boundary
5703  const unsigned nbound_ele = tmp_face_ele_pt.size();
5704  for (unsigned ie = 0; ie < nbound_ele; ie++)
5705  {
5706  // Get the possible main element
5707  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5708  if (!done_face[main_face_ele_pt])
5709  {
5710  // Mark the face element as done
5711  done_face[main_face_ele_pt] = true;
5712  // Get the number of nodes for the face element
5713  const unsigned nnodes = main_face_ele_pt->nnode();
5714  // Get the first and last node of the main face element
5715  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5716  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5717  // Look for the other side face element
5718  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5719  {
5720  // Get the possible dependant element
5721  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5722  if (!done_face[dependant_face_ele_pt])
5723  {
5724  // Get the first and last node of the dependant face element
5725  Node* dependant_first_node_pt =
5726  dependant_face_ele_pt->node_pt(0);
5727  Node* dependant_last_node_pt =
5728  dependant_face_ele_pt->node_pt(nnodes-1);
5729  // Check if the nodes at the ends of both face elements
5730  // match (also check the reversed case)
5731  if (((dependant_first_node_pt == main_first_node_pt) &&
5732  (dependant_last_node_pt == main_last_node_pt)) ||
5733  ((dependant_first_node_pt == main_last_node_pt) &&
5734  (dependant_last_node_pt == main_first_node_pt)))
5735  {
5736 #ifdef PARANOID
5737  // Increase the number of found face elements
5738  nfound_face_elements+=2;
5739 #endif
5740  // Set the flag to indicate we are working with an
5741  // internal boundary
5742  is_internal_boundary = true;
5743  // Mark the face element as done
5744  done_face[dependant_face_ele_pt] = true;
5745 
5746  // Now choose which face element will be used as the main
5747  // element. Use the same criteria as the compute segments
5748  // connectivity method (highest processor in charge or
5749  // bottom-left bulk element)
5750 
5751  // Get the bulk element for each face element (the main
5752  // and the dependant face element)
5753  FiniteElement *main_bulk_ele_pt =
5754  face_to_bulk_element_pt[main_face_ele_pt];
5755  FiniteElement *dependant_bulk_ele_pt =
5756  face_to_bulk_element_pt[dependant_face_ele_pt];
5757 
5758  // Get the processor in charge for each bulk element
5759  int processor_in_charge_main_bulk_ele =
5760  main_bulk_ele_pt->non_halo_proc_ID();
5761  int processor_in_charge_dependant_bulk_ele =
5762  dependant_bulk_ele_pt->non_halo_proc_ID();
5763 
5764  // If the processor in charge is negative the element is
5765  // not halo, therefore the processor in charge is the
5766  // current one
5767  if (processor_in_charge_main_bulk_ele < 0)
5768  {
5769  processor_in_charge_main_bulk_ele=static_cast<int>(my_rank);
5770  }
5771  if (processor_in_charge_dependant_bulk_ele < 0)
5772  {
5773  processor_in_charge_dependant_bulk_ele=static_cast<int>(my_rank);
5774  }
5775 
5776  // Flag to know if add the main or dependant face element
5777  bool add_main_face_element = true;
5778  if (processor_in_charge_dependant_bulk_ele >
5779  processor_in_charge_main_bulk_ele)
5780  {
5781  // Include the dependant element
5782  add_main_face_element = false;
5783  }
5784  else if (processor_in_charge_main_bulk_ele ==
5785  processor_in_charge_dependant_bulk_ele)
5786  {
5787  // When the processor in charge for both elements is the same
5788  // then use the bottom-left criteria on the bulk elements to
5789  // choose the main face element
5790  Vector<double> main_ele_coordinates(2);
5791  Vector<double> dependant_ele_coordinates(2);
5792  // Get the number of nodes on the bulk elements
5793  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5794  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5795  {
5796  for (unsigned idim = 0; idim < 2; idim++)
5797  {
5798  main_ele_coordinates[idim]+=
5799  main_bulk_ele_pt->node_pt(inode)->x(idim);
5800  dependant_ele_coordinates[idim]+=
5801  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5802  } // (idim < 2)
5803  } // (inode < n_bulk_nodes)
5804 
5805  // Get the average of the nodes coordinates
5806  for (unsigned idim = 0; idim < 2; idim++)
5807  {
5808  main_ele_coordinates[idim]/=(double)n_bulk_nodes;
5809  dependant_ele_coordinates[idim]/=(double)n_bulk_nodes;
5810  }
5811 
5812  // Once we know the average coordinates for each element
5813  // then we choose the one with the bottom-left averaged
5814  // coordinates
5815  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5816  {add_main_face_element = false;}
5817  else if(dependant_ele_coordinates[1]==main_ele_coordinates[1])
5818  {
5819  // The left-most element
5820  if(dependant_ele_coordinates[0] < main_ele_coordinates[0])
5821  {add_main_face_element = false;}
5822  }
5823  } // else -- The processor in charge is the same for both
5824  // elements
5825 
5826  if (add_main_face_element)
5827  {
5828  // Add the main face element to the storage so we get
5829  // the halo and haloed nodes from these face element
5830  face_ele_pt.push_back(main_face_ele_pt);
5831  }
5832  else
5833  {
5834  // Add the main face element to the storage so we get
5835  // the halo and haloed nodes from these face element
5836  face_ele_pt.push_back(dependant_face_ele_pt);
5837  }
5838 
5839  // Break the for to look for the next face element
5840  break;
5841 
5842  } // if -- matching of nodes from main ele and dependant ele
5843  } // if (!done_face[dependant_face_ele_pt])
5844  } // for (iie < nbound_ele)
5845  } // if (!done_face[main_face_ele_pt])
5846  } // for (ie < nbound_ele)
5847 
5848  // Get the number of face elements
5849  const unsigned nface_ele = face_ele_pt.size();
5850 
5851 #ifdef PARANOID
5852  // Check if we are working with an internal open curve. First check
5853  // if there are elements, in a distributed approach they may be no
5854  // elements associated to the boundary
5855  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5856  {is_internal_boundary_paranoid = true;}
5857 
5858  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5859  nbound_ele!=nface_ele*2)
5860  {
5861  std::ostringstream error_message;
5862  error_message
5863  << "The info. to perform the synchronisation of the boundary "
5864  << "coordinates was not completely established\n"
5865  << "In this case it was the number of non repeated boundary elements\n"
5866  << "Number of boundary elements: (" << nbound_ele << ")\n"
5867  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5868  throw OomphLibError(error_message.str(),
5869  "TriangleMesh::synchronize_boundary_coordinates()",
5870  OOMPH_EXCEPTION_LOCATION);
5871  }
5872 #endif
5873 
5874  // ----------------------------------------------------------------
5875  // Second: Identify the halo face elements
5876  // ----------------------------------------------------------------
5877 
5878  // A flag vector to mark those face elements that are considered as
5879  // halo in the current processor
5880  std::vector<bool> is_halo_face_element(nface_ele, false);
5881 
5882  // Count the total number of non halo face elements
5883  unsigned nnon_halo_face_elements = 0;
5884 
5885  for (unsigned ie = 0; ie < nface_ele; ie++)
5886  {
5887  FiniteElement* face_el_pt = face_ele_pt[ie];
5888  // Get the bulk element
5889  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5890  // Check if the bulk element is halo
5891  if (!tmp_bulk_ele_pt->is_halo())
5892  {
5893  is_halo_face_element[ie] = false;
5894  nnon_halo_face_elements++;
5895  }
5896  else
5897  {
5898  // Mark the face element as halo
5899  is_halo_face_element[ie] = true;
5900  }
5901  } // for (ie < nface_ele)
5902 
5903  // -----------------------------------------------------------------
5904  // Third: Go through the face elements and get the nodes from the
5905  // elements. The boundary coordinate from each node is sent to its
5906  // processor in charge, then that processor will be responsible to
5907  // send the bound coordinate to all the processors that have a halo
5908  // representation of the node
5909  // -----------------------------------------------------------------
5910 
5911  // A map to know which nodes are already done
5912  std::map<Node*,bool> done_node;
5913 
5914  // The storage for the halo nodes on face elements in this processor
5915  // with other processors
5916  Vector<Vector<Node*> > face_halo_node_pt(nproc);
5917 
5918  // The storage for the ids of the halo nodes on face elements in
5919  // this processor with other processors
5920  Vector<Vector<unsigned> > face_halo_node_id(nproc);
5921 
5922  // The storage for the haloed nodes on face elements in this
5923  // processor with other processors
5924  Vector<Vector<Node*> > face_haloed_node_pt(nproc);
5925 
5926  // The storage for the ids of the haloed nodes on face elements in
5927  // this processor with other processors
5928  Vector<Vector<unsigned> > face_haloed_node_id(nproc);
5929 
5930  // A map to know which nodes are face nodes and the processor in
5931  // charge is the current one
5932  std::map<Node*,bool> done_haloed_face_node;
5933 
5934  // Go through all the face elements
5935  for (unsigned iface = 0; iface < nface_ele; iface++)
5936  {
5937  // Only work with the non halo face elements
5938  if (!is_halo_face_element[iface])
5939  {
5940  // Get the face element
5941  FiniteElement *ele_face_pt = face_ele_pt[iface];
5942  // The number of nodes of the face elements
5943  const unsigned nnodes = ele_face_pt->nnode();
5944  // Go through all the nodes in the face element
5945  for (unsigned in = 0; in < nnodes; in++)
5946  {
5947  Node* face_node_pt = ele_face_pt->node_pt(in);
5948  // Check if node is done
5949  if (!done_node[face_node_pt])
5950  {
5951  // Mark the node as done
5952  done_node[face_node_pt] = true;
5953  // First check if the node is halo
5954  if (face_node_pt->is_halo())
5955  {
5956  // Get the processor in charge for the current node
5957  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5958 #ifdef PARANOID
5959  if (int_nonhalo_ID < 0)
5960  {
5961  std::ostringstream error_message;
5962  error_message
5963  << "The node was marked to be halo but the processor in "
5964  << "charge was found to be -1\n\n";
5965  throw OomphLibError(error_message.str(),
5966  "TriangleMesh::synchronize_boundary_coordinates()",
5967  OOMPH_EXCEPTION_LOCATION);
5968  }
5969 #endif
5970  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
5971  // Add the node to the structure that holds the halo
5972  // nodes, the current processor will need to send the
5973  // info. to the processor in charge.
5974  face_halo_node_pt[ip].push_back(face_node_pt);
5975  // ... finally look for the halo id with the processor in
5976  // charge
5977 #ifdef PARANOID
5978  bool found_halo_node = false;
5979 #endif
5980  const unsigned nhalo_iproc = this->nhalo_node(ip);
5981  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
5982  {
5983  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
5984  if (compare_face_node_pt == face_node_pt)
5985  {
5986  // Once found the id of the node with the processor
5987  // store the id in the proper storage
5988  face_halo_node_id[ip].push_back(ihn);
5989 #ifdef PARANOID
5990  // Set the flag to mark as found the halo node
5991  found_halo_node = true;
5992 #endif
5993  // Break the loop
5994  break;
5995  }
5996  } // for (ih < nhalo_iproc)
5997 #ifdef PARANOID
5998  if (!found_halo_node)
5999  {
6000  std::ostringstream error_message;
6001  error_message
6002  << "The halo id of the current node: ("
6003  << face_node_pt->x(0) << ", " << face_node_pt->x(1)
6004  << ") with processor (" << ip << ") was not found!!!\n\n";
6005  throw OomphLibError(error_message.str(),
6006  "TriangleMesh::synchronize_boundary_coordinates()",
6007  OOMPH_EXCEPTION_LOCATION);
6008  }
6009 #endif
6010  } // if (face_node_pt->is_halo())
6011  // If the node is not halo then it could be haloed. If that
6012  // is the case then store the processors at which the node
6013  // is haloed and its id. The info. of these nodes will be
6014  // sent to all the processors with a halo counterpart
6015  else
6016  {
6017  for (unsigned ip = 0; ip < nproc; ip++)
6018  {
6019  // Only work with processors different that the current one
6020  if (ip != my_rank)
6021  {
6022  // If the node is found to be haloed with the "ip"
6023  // processor then save the haloed id in the storage.
6024  // The current processor needs to send info. to the
6025  // other processors to establish the boundary
6026  // coordinates
6027 
6028  // Get the number of haloed nodes with processor ip
6029  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6030  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6031  {
6032  Node* compare_face_node_pt=this->haloed_node_pt(ip, ihdn);
6033  if (face_node_pt == compare_face_node_pt)
6034  {
6035  // Store the node on the haloed node vector for
6036  // the corresponding processor
6037  face_haloed_node_pt[ip].push_back(face_node_pt);
6038  // Now store the halo id of the node with the
6039  // current processor
6040  face_haloed_node_id[ip].push_back(ihdn);
6041  // Mark the node as haloed with other processors,
6042  // so we know the processor in charge is the
6043  // current one "my_rank".
6044  done_haloed_face_node[face_node_pt] = true;
6045  // Break looking in the current processor, look in
6046  // the next one
6047  break;
6048  } // if (face_node_pt == compare_face_node_pt)
6049  } // for (ihdn < nhaloed_node_iproc)
6050  } // if (ip != my_rank)
6051  } // for (ip < nproc)
6052  } // else (non halo node)
6053  } // if (!done_node[node_face_pt])
6054  } // for (in < nnodes)
6055  } // if (!is_halo_face_element[iface])
6056  } // for (iface < nface_ele)
6057 
6058  // -----------------------------------------------------------------
6059  // Fourth: Go through the halo nodes, package and send the
6060  // info. necessary to identify the face nodes in the processor in
6061  // charge. Identify the haloed nodes in the processor in charge and
6062  // establish the boundary coordinates, check if those nodes are
6063  // (already) marked as faced nodes, if that is the case then do not
6064  // establish the boundary coordinates but register them to send back
6065  // the info. to all the processors that have a halo representation
6066  // of the face node
6067  // -----------------------------------------------------------------
6068 
6069  // Go through all processors
6070  for (unsigned ip = 0; ip < nproc; ip++)
6071  {
6072  // Only work with processors different than the current one
6073  if (ip != my_rank)
6074  {
6075  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6076 #ifdef PARANOID
6077  if (nhalo_face_nodes!=face_halo_node_id[ip].size())
6078  {
6079  std::ostringstream error_message;
6080  error_message
6081  << "The number of found halo face nodes (" << nhalo_face_nodes
6082  << ") is different from the number of\nfound halo face ids ("
6083  << face_halo_node_id[ip].size() << ")!!!\n\n";
6084  throw OomphLibError(error_message.str(),
6085  "TriangleMesh::synchronize_boundary_coordinates()",
6086  OOMPH_EXCEPTION_LOCATION);
6087  }
6088 #endif
6089 
6090  // Container to send the info. related with the halo nodes to be
6091  // identified in the processors in charge
6092  Vector<unsigned> flat_unsigned_send_packed_data;
6093  Vector<double> flat_double_send_packed_data;
6094 
6095  // Go through the halo face nodes in the "ip" processor
6096  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6097  {
6098  // Get the "ihfn"-th face node with the "ip" processor
6099  Node *halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6100  // Get the halo id with the "ip" processor
6101  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6102  // Get the boundary coordinate of the node
6103  Vector<double> zeta(1);
6104  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6105  // Store the info. in the containers
6106  flat_unsigned_send_packed_data.push_back(halo_id);
6107  flat_double_send_packed_data.push_back(zeta[0]);
6108  }
6109 
6110  // Send the info.
6111  MPI_Status status;
6112  MPI_Request request;
6113 
6114  // Processor to which send the info
6115  int send_proc = static_cast<int>(ip);
6116  // Processor from which receive the info
6117  int receive_proc = static_cast<int>(ip);
6118 
6119  // Storage to receive the info.
6120  Vector<unsigned> flat_unsigned_receive_packed_data;
6121  Vector<double> flat_double_receive_packed_data;
6122 
6123  // --------------
6124  // Unsigned data
6125  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6126  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6127  send_proc,1,comm_pt->mpi_comm(),&request);
6128 
6129  unsigned nflat_unsigned_receive = 0;
6130  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6131  receive_proc,1,comm_pt->mpi_comm(),&status);
6132 
6133  MPI_Wait(&request,MPI_STATUS_IGNORE);
6134 
6135  if (nflat_unsigned_send!=0)
6136  {
6137  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6138  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6139  }
6140 
6141  if (nflat_unsigned_receive!=0)
6142  {
6143  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6144  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6145  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6146  }
6147 
6148  if (nflat_unsigned_send!=0)
6149  {
6150  MPI_Wait(&request,MPI_STATUS_IGNORE);
6151  }
6152 
6153  // --------------
6154  // Double data
6155  unsigned nflat_double_send = flat_double_send_packed_data.size();
6156  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6157  send_proc,3,comm_pt->mpi_comm(),&request);
6158 
6159  unsigned nflat_double_receive = 0;
6160  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6161  receive_proc,3,comm_pt->mpi_comm(),&status);
6162 
6163  MPI_Wait(&request,MPI_STATUS_IGNORE);
6164 
6165  if (nflat_double_send!=0)
6166  {
6167  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6168  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6169  }
6170 
6171  if (nflat_double_receive!=0)
6172  {
6173  flat_double_receive_packed_data.resize(nflat_double_receive);
6174  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6175  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6176  }
6177 
6178  if (nflat_double_send!=0)
6179  {
6180  MPI_Wait(&request,MPI_STATUS_IGNORE);
6181  }
6182  // --------------
6183 
6184 #ifdef PARANOID
6185  if (nflat_unsigned_receive!=nflat_double_receive)
6186  {
6187  std::ostringstream error_message;
6188  error_message
6189  << "The number of unsigned received data ("
6190  << nflat_unsigned_receive << ") is different from the "
6191  << "number\nof double received data ("
6192  << nflat_double_receive << ")!!!\n\n";
6193  throw OomphLibError(error_message.str(),
6194  "TriangleMesh::synchronize_boundary_coordinates()",
6195  OOMPH_EXCEPTION_LOCATION);
6196  }
6197 #endif
6198 
6199  // With the received info. establish the boundary coordinates
6200  // for the face nodes that this processor is in charge (haloed
6201  // nodes)
6202  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6203  iflat_packed++)
6204  {
6205  // Get the haloed id for the node
6206  const unsigned haloed_id =
6207  flat_unsigned_receive_packed_data[iflat_packed];
6208  // Get the boundary coordinates
6209  Vector<double> zeta(1);
6210  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6211 
6212  // Get the haloed node
6213  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6214 
6215  // If the node has already set the boundary coordinates then
6216  // do not establish it. This is the case for the nodes that
6217  // lie on the boundary, for those nodes not identified on the
6218  // boundary since no elements lie on the boundary but the node
6219  // is on the boundary (a corner of an element lies on the
6220  // boundary) set boundary coordinates and register them to
6221  // send their info. to the processors with a halo counterpart
6222 
6223  // If the node is not haloed face in the procesor in charge
6224  // then set the boundary coordinates and register the node to
6225  // send back the boundary coordinates to the processors with a
6226  // halo counterpart
6227  if (!done_haloed_face_node[haloed_face_node_pt])
6228  {
6229  // Establish the boundary coordinates
6230  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6231 
6232  // Look in all processors where the node could be halo
6233  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6234  {
6235  // Only work with processors different than the current one
6236  if (iiproc != my_rank)
6237  {
6238  // Get the number of haloed nodes with processor iiproc
6239  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6240  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6241  {
6242  Node* compare_haloed_node_pt=this->haloed_node_pt(iiproc,ihdn);
6243  if (haloed_face_node_pt == compare_haloed_node_pt)
6244  {
6245  // Store the node on the haloed node vector for the
6246  // corresponding processor
6247  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6248  // Now store the halo id of the node with the current
6249  // processor
6250  face_haloed_node_id[iiproc].push_back(ihdn);
6251  // Break searching in the current processor, search in
6252  // the next one
6253  break;
6254  }// if (haloed_face_node_pt==compare_haloed_face_node_pt)
6255  } // for (ihdn < nhaloed_node_iproc)
6256  } // if (iiproc != my_rank)
6257  } // for (iiproc < nproc)
6258  } // if (!done_haloed_face_node[haloed_face_node_pt])
6259  } // for (iflat_packed < nflat_unsigned_receive)
6260  } // if (ip != my_rank)
6261  } // for (ip < nproc)
6262 
6263  // -----------------------------------------------------------------
6264  // Fifth: The boundary coordinates have been established in the
6265  // processors in charge of the nodes. Now each processor send back
6266  // the boundary coordinates to all the processors where there is a
6267  // halo representation of the node
6268  // -----------------------------------------------------------------
6269 
6270  // Go through all processors
6271  for (unsigned ip = 0; ip < nproc; ip++)
6272  {
6273  // Only work with processors different than the current one
6274  if (ip != my_rank)
6275  {
6276  // Container to send the info. of the haloed nodes to all the
6277  // processors
6278  Vector<unsigned> flat_unsigned_send_packed_data;
6279  Vector<double> flat_double_send_packed_data;
6280 
6281  // Get the total number of haloed face nodes with the "ip"
6282  // processor
6283  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6284  // Go through the haloed face nodes in the "ip" processor
6285  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6286  {
6287  // Get the "ihdfn"-th face node with the "ip" processor
6288  Node *haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6289  // Get the haloed id with the "ip" processor
6290  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6291  // Get the boundary coordinate of the node
6292  Vector<double> zeta(1);
6293  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6294  // Store the info. in the containers
6295  flat_unsigned_send_packed_data.push_back(haloed_id);
6296  flat_double_send_packed_data.push_back(zeta[0]);
6297  }
6298 
6299  // Send the info.
6300  MPI_Status status;
6301  MPI_Request request;
6302 
6303  // Processor to which send the info
6304  int send_proc = static_cast<int>(ip);
6305  // Processor from which receive the info
6306  int receive_proc = static_cast<int>(ip);
6307 
6308  // Storage to receive the info.
6309  Vector<unsigned> flat_unsigned_receive_packed_data;
6310  Vector<double> flat_double_receive_packed_data;
6311 
6312  // --------------
6313  // Unsigned data
6314  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6315  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6316  send_proc,1,comm_pt->mpi_comm(),&request);
6317 
6318  unsigned nflat_unsigned_receive = 0;
6319  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6320  receive_proc,1,comm_pt->mpi_comm(),&status);
6321 
6322  MPI_Wait(&request,MPI_STATUS_IGNORE);
6323 
6324  if (nflat_unsigned_send!=0)
6325  {
6326  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6327  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6328  }
6329 
6330  if (nflat_unsigned_receive!=0)
6331  {
6332  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6333  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6334  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6335  }
6336 
6337  if (nflat_unsigned_send!=0)
6338  {
6339  MPI_Wait(&request,MPI_STATUS_IGNORE);
6340  }
6341 
6342  // --------------
6343  // Double data
6344  unsigned nflat_double_send = flat_double_send_packed_data.size();
6345  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6346  send_proc,3,comm_pt->mpi_comm(),&request);
6347 
6348  unsigned nflat_double_receive = 0;
6349  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6350  receive_proc,3,comm_pt->mpi_comm(),&status);
6351 
6352  MPI_Wait(&request,MPI_STATUS_IGNORE);
6353 
6354  if (nflat_double_send!=0)
6355  {
6356  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6357  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6358  }
6359 
6360  if (nflat_double_receive!=0)
6361  {
6362  flat_double_receive_packed_data.resize(nflat_double_receive);
6363  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6364  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6365  }
6366 
6367  if (nflat_double_send!=0)
6368  {
6369  MPI_Wait(&request,MPI_STATUS_IGNORE);
6370  }
6371  // --------------
6372 
6373 #ifdef PARANOID
6374  if (nflat_unsigned_receive!=nflat_double_receive)
6375  {
6376  std::ostringstream error_message;
6377  error_message
6378  << "The number of unsigned received data ("
6379  << nflat_unsigned_receive << ") is different from the "
6380  << "number\nof double received data ("
6381  << nflat_double_receive << ")!!!\n\n";
6382  throw OomphLibError(error_message.str(),
6383  "TriangleMesh::synchronize_boundary_coordinates()",
6384  OOMPH_EXCEPTION_LOCATION);
6385  }
6386 #endif
6387 
6388  // With the received info. establish the boundary coordinates
6389  // received for the face nodes that this processor is not in
6390  // charge (halo nodes)
6391  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6392  iflat_packed++)
6393  {
6394  // Get the halo id for the node
6395  const unsigned halo_id =
6396  flat_unsigned_receive_packed_data[iflat_packed];
6397  // Get the boundary coordinates
6398  Vector<double> zeta(1);
6399  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6400 
6401  // Get the halo node
6402  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6403 
6404  // It could be possible that the node has been already
6405  // established boundary coordinates since it is a halo face
6406  // node. However, for those elements not on the boundary, but
6407  // having a corner node on the boundary this procedure will
6408  // establish boundary coordinates for those nodes
6409 
6410  //this->add_boundary_node(b, halo_face_node_pt);
6411 
6412  // Establish the boundary coordinates
6413  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6414  } // for (iflat_packed < nflat_unsigned_receive)
6415  } // if (ip != my_rank)
6416  } // for (ip < nproc)
6417 
6418  // Clean all the created face elements
6419  for (unsigned ie = 0; ie < nbound_ele; ie++)
6420  {
6421  delete tmp_face_ele_pt[ie];
6422  tmp_face_ele_pt[ie] = 0;
6423  }
6424 
6425  // Now get a new face mesh representation and fill the data for those
6426  // processors with halo segments
6427  if (is_internal_boundary)
6428  {
6429  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6430  }
6431 
6432  }
6433 
6434  //======================================================================
6435  /// \short Re-assign the boundary segments initial zeta (arclength)
6436  /// for those internal boundaries that were splited during the
6437  /// distribution process (only apply for internal boundaries that
6438  /// have one face element at each side of the boundary)
6439  //======================================================================
6440  template<class ELEMENT>
6443  const unsigned& b)
6444  {
6445  // ------------------------------------------------------------------
6446  // First: Get the face elements associated with the current boundary
6447  // Only include nonhalo face elements
6448  // ------------------------------------------------------------------
6449  // Temporary storage for face elements
6450  Vector<FiniteElement*> face_el_pt;
6451 
6452  // Temporary storage for the number of elements adjacent to the
6453  // boundary
6454  unsigned nele = 0;
6455 
6456  // Temporary storage for elements adjacent to the boundary that have
6457  // a common edge (related with internal boundaries)
6458  unsigned n_repeated_ele = 0;
6459 
6460  const unsigned n_regions = this->nregion();
6461 
6462  // Temporary storage for already done nodes
6463  Vector<std::pair<Node*, Node*> > done_nodes_pt;
6464 
6465  // If there is more than one region then only use boundary
6466  // coordinates from the bulk side (region 0)
6467  if (n_regions > 1)
6468  {
6469  for (unsigned rr = 0 ; rr < n_regions; rr++)
6470  {
6471  const unsigned region_id =
6472  static_cast<unsigned>(this->Region_attribute[rr]);
6473 
6474  // Loop over all elements on boundaries in region i_r
6475  const unsigned nel_in_region =
6476  this->nboundary_element_in_region(b, region_id);
6477 
6478  unsigned nel_repetead_in_region = 0;
6479 
6480  // Only bother to do anything else, if there are elements
6481  // associated with the boundary and the current region
6482  if (nel_in_region > 0)
6483  {
6484  bool repeated = false;
6485 
6486  // Loop over the bulk elements adjacent to boundary b
6487  for (unsigned e = 0; e < nel_in_region; e++)
6488  {
6489  // Get pointer to the bulk element that is adjacent to
6490  // boundary b
6491  FiniteElement* bulk_elem_pt =
6492  this->boundary_element_in_region_pt(b, region_id, e);
6493 
6494  // Remember only to work with nonhalo elements
6495  if (bulk_elem_pt->is_halo())
6496  {
6497  n_repeated_ele++;
6498  continue;
6499  }
6500 
6501  // Find the index of the face of element e along boundary b
6502  int face_index =
6503  this->face_index_at_boundary_in_region(b,region_id,e);
6504 
6505  // Before adding the new element we need to be sure that the
6506  // edge that this element represent has not been already
6507  // added
6508  FiniteElement* tmp_ele_pt =
6509  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6510 
6511  const unsigned n_nodes = tmp_ele_pt->nnode();
6512 
6513  std::pair<Node*, Node*> tmp_pair =
6514  std::make_pair(tmp_ele_pt->node_pt(0),
6515  tmp_ele_pt->node_pt(n_nodes - 1));
6516 
6517  std::pair<Node*, Node*> tmp_pair_inverse =
6518  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6519  tmp_ele_pt->node_pt(0));
6520 
6521  // Search for repeated nodes
6522  const unsigned n_done_nodes = done_nodes_pt.size();
6523  for (unsigned l = 0; l < n_done_nodes; l++)
6524  {
6525  if (tmp_pair == done_nodes_pt[l] ||
6526  tmp_pair_inverse == done_nodes_pt[l])
6527  {
6528  nel_repetead_in_region++;
6529  repeated = true;
6530  break;
6531  }
6532  }
6533 
6534  // Create new face element
6535  if (!repeated)
6536  {
6537  // Add the pair of nodes (edge) to the node dones
6538  done_nodes_pt.push_back(tmp_pair);
6539  // Add the element to the face elements
6540  face_el_pt.push_back(tmp_ele_pt);
6541  }
6542  else
6543  {
6544  // Clean up
6545  delete tmp_ele_pt;
6546  tmp_ele_pt = 0;
6547  }
6548 
6549  // Re-start
6550  repeated = false;
6551 
6552  } // for nel
6553 
6554  nele += nel_in_region;
6555 
6556  n_repeated_ele += nel_repetead_in_region;
6557 
6558  } // if (nel_in_region > 0)
6559  } // for (rr < n_regions)
6560  } // if (n_regions > 1)
6561  //Otherwise it's just the normal boundary functions
6562  else
6563  {
6564  // Loop over all elements on boundaries
6565  nele = this->nboundary_element(b);
6566 
6567  //Only bother to do anything else, if there are elements
6568  if (nele > 0)
6569  {
6570  // Check for repeated ones
6571  bool repeated = false;
6572 
6573  // Loop over the bulk elements adjacent to boundary b
6574  for (unsigned e = 0; e < nele; e++)
6575  {
6576  // Get pointer to the bulk element that is adjacent to
6577  // boundary b
6578  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6579 
6580  // Remember only to work with nonhalo elements
6581  if (bulk_elem_pt->is_halo())
6582  {
6583  n_repeated_ele++;
6584  // Skip the halo element
6585  continue;
6586  }
6587 
6588  //Find the index of the face of element e along boundary b
6589  int face_index = this->face_index_at_boundary(b, e);
6590 
6591  // Before adding the new element we need to be sure that the
6592  // edge that this element represents has not been already
6593  // added (only applies for internal boundaries)
6594  FiniteElement* tmp_ele_pt =
6595  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6596 
6597  const unsigned n_nodes = tmp_ele_pt->nnode();
6598 
6599  std::pair<Node*, Node*> tmp_pair =
6600  std::make_pair(tmp_ele_pt->node_pt(0),
6601  tmp_ele_pt->node_pt(n_nodes - 1));
6602 
6603  std::pair<Node*, Node*> tmp_pair_inverse =
6604  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6605  tmp_ele_pt->node_pt(0));
6606 
6607  // Search for repeated nodes
6608  const unsigned n_done_nodes = done_nodes_pt.size();
6609  for (unsigned l = 0; l < n_done_nodes; l++)
6610  {
6611  if (tmp_pair == done_nodes_pt[l] ||
6612  tmp_pair_inverse == done_nodes_pt[l])
6613  {
6614  // Increase the number of repeated elements
6615  n_repeated_ele++;
6616  // Mark the element as repeated
6617  repeated = true;
6618  break;
6619  }
6620  }
6621 
6622  // Create new face element
6623  if (!repeated)
6624  {
6625  // Add the pair of nodes (edge) to the node dones
6626  done_nodes_pt.push_back(tmp_pair);
6627  // Add the element to the face elements
6628  face_el_pt.push_back(tmp_ele_pt);
6629  }
6630  else
6631  {
6632  // Free the repeated bulk element!!
6633  delete tmp_ele_pt;
6634  tmp_ele_pt = 0;
6635  }
6636 
6637  // Re-start
6638  repeated = false;
6639 
6640  } // for (e < nel)
6641  } // if (nel > 0)
6642 
6643  } // else (n_regions > 1)
6644 
6645  // Do not consider the repeated elements
6646  nele-= n_repeated_ele;
6647 
6648 #ifdef PARANOID
6649  if (nele!=face_el_pt.size())
6650  {
6651  std::ostringstream error_message;
6652  error_message
6653  << "The independet counting of face elements ("<<nele<<") for "
6654  << "boundary ("<<b<<") is different\n"
6655  << "from the real number of face elements in the container ("
6656  << face_el_pt.size() <<")\n";
6657  //<< "Possible memory leak\n"
6658  throw OomphLibError(error_message.str(),
6659  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6660  OOMPH_EXCEPTION_LOCATION);
6661  }
6662 #endif
6663 
6664  // ----------------------------------------------------------------
6665  // Second: Sort the face elements (to create segments), only
6666  // consider nonhalo elements
6667  // ----------------------------------------------------------------
6668 
6669  // Get the total number of nonhalo face elements
6670  const unsigned nnon_halo_face_elements = face_el_pt.size();
6671 
6672  // The vector of list to store the "segments" that compound the
6673  // boundary (segments may appear only in a distributed mesh)
6674  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
6675 
6676  // Number of already sorted face elements
6677  unsigned nsorted_face_elements = 0;
6678 
6679  // Keep track of who's done
6680  std::map<FiniteElement*, bool> done_el;
6681 
6682  // Keep track of which element is inverted
6683  std::map<FiniteElement*, bool> is_inverted;
6684 
6685  // Iterate until all possible segments have been created
6686  while(nsorted_face_elements < nnon_halo_face_elements)
6687  {
6688  // The ordered list of face elements (in a distributed mesh a
6689  // collection of contiguous face elements define a segment)
6690  std::list<FiniteElement*> sorted_el_pt;
6691 
6692 #ifdef PARANOID
6693  // Select an initial element for the segment
6694  bool found_initial_face_element = false;
6695 #endif
6696 
6697  FiniteElement* ele_face_pt = 0;
6698 
6699  unsigned iface = 0;
6700  for (iface = 0; iface < nele; iface++)
6701  {
6702  ele_face_pt = face_el_pt[iface];
6703  // If not done then take it as initial face element
6704  if (!done_el[ele_face_pt])
6705  {
6706 #ifdef PARANOID
6707  found_initial_face_element = true;
6708 #endif
6709  nsorted_face_elements++;
6710  iface++; // The next element number
6711  sorted_el_pt.push_back(ele_face_pt);
6712  // Mark as done
6713  done_el[ele_face_pt] = true;
6714  break;
6715  }
6716  } // for (iface < nele)
6717 
6718 #ifdef PARANOID
6719  if (!found_initial_face_element)
6720  {
6721  std::ostringstream error_message;
6722  error_message
6723  <<"Could not find an initial face element for the current segment\n";
6724  // << "----- Possible memory leak -----\n";
6725  throw OomphLibError(error_message.str(),
6726  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6727  OOMPH_EXCEPTION_LOCATION);
6728  }
6729 #endif
6730 
6731  // Number of nodes
6732  const unsigned nnod = ele_face_pt->nnode();
6733 
6734  // Left and rightmost nodes (the left and right nodes of the
6735  // current face element)
6736  Node* left_node_pt = ele_face_pt->node_pt(0);
6737  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6738 
6739  // Continue iterating if a new face element has been added to the
6740  // list
6741  bool face_element_added = false;
6742 
6743  // While a new face element has been added to the set of sorted
6744  // face elements then re-iterate
6745  do
6746  {
6747  // Start from the next face element since we have already added
6748  // the previous one as the initial face element (any previous
6749  // face element had to be added on previous iterations)
6750  for (unsigned iiface = iface; iiface < nele; iiface++)
6751  {
6752  // Re-start flag
6753  face_element_added = false;
6754 
6755  // Get the candidate element
6756  ele_face_pt = face_el_pt[iiface];
6757 
6758  // Check that the candidate element has not been done
6759  if (!(done_el[ele_face_pt]))
6760  {
6761  // Get the left and right nodes of the current element
6762  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6763  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6764 
6765  // New element fits at the left of segment and is not inverted
6766  if (left_node_pt == local_right_node_pt)
6767  {
6768  left_node_pt = local_left_node_pt;
6769  sorted_el_pt.push_front(ele_face_pt);
6770  is_inverted[ele_face_pt] = false;
6771  face_element_added = true;
6772  }
6773  // New element fits at the left of segment and is inverted
6774  else if (left_node_pt == local_left_node_pt)
6775  {
6776  left_node_pt = local_right_node_pt;
6777  sorted_el_pt.push_front(ele_face_pt);
6778  is_inverted[ele_face_pt] = true;
6779  face_element_added = true;
6780  }
6781  // New element fits on the right of segment and is not inverted
6782  else if (right_node_pt == local_left_node_pt)
6783  {
6784  right_node_pt = local_right_node_pt;
6785  sorted_el_pt.push_back(ele_face_pt);
6786  is_inverted[ele_face_pt] = false;
6787  face_element_added = true;
6788  }
6789  // New element fits on the right of segment and is inverted
6790  else if (right_node_pt == local_right_node_pt)
6791  {
6792  right_node_pt = local_left_node_pt;
6793  sorted_el_pt.push_back(ele_face_pt);
6794  is_inverted[ele_face_pt] = true;
6795  face_element_added = true;
6796  }
6797 
6798  if (face_element_added)
6799  {
6800  done_el[ele_face_pt] = true;
6801  nsorted_face_elements++;
6802  break;
6803  }
6804 
6805  } // if (!(done_el[ele_face_pt]))
6806  } // for (iiface<nnon_halo_face_element)
6807  }while(face_element_added &&
6808  (nsorted_face_elements < nnon_halo_face_elements));
6809 
6810  // Store the created segment in the vector of segments
6811  segment_sorted_ele_pt.push_back(sorted_el_pt);
6812 
6813  } // while(nsorted_face_elements < nnon_halo_face_elements);
6814 
6815  // --------------------------------------------------------------
6816  // Third: We have the face elements sorted, now assign boundary
6817  // coordinates to the nodes in the segments and compute the
6818  // arclength of the segment
6819  // --------------------------------------------------------------
6820 
6821  // Vector of sets that stores the nodes of each segment based on a
6822  // lexicographically order starting from the bottom left node of
6823  // each segment
6824  Vector<std::set<Node*> > segment_all_nodes_pt;
6825 
6826  // The number of segments in this processor
6827  const unsigned nsegments = segment_sorted_ele_pt.size();
6828 
6829 #ifdef PARANOID
6830  if (nnon_halo_face_elements > 0 && nsegments == 0)
6831  {
6832  std::ostringstream error_message;
6833  error_message
6834  << "The number of segments is zero, but the number of nonhalo\n"
6835  << "elements is: (" << nnon_halo_face_elements << ")\n";
6836  throw OomphLibError(error_message.str(),
6837  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6838  OOMPH_EXCEPTION_LOCATION);
6839  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6840 #endif
6841 
6842  // The arclength of each segment in the current processor
6843  Vector<double> segment_arclength(nsegments);
6844 
6845  // The initial zeta for the segment
6846  Vector<double> initial_zeta_segment(nsegments);
6847 
6848  // The final zeta for the segment
6849  Vector<double> final_zeta_segment(nsegments);
6850 
6851  // Go through all the segments and compute the LOCAL boundary
6852  // coordinates
6853  for (unsigned is = 0; is < nsegments; is++)
6854  {
6855 #ifdef PARANOID
6856  if (segment_sorted_ele_pt[is].size() == 0)
6857  {
6858  std::ostringstream error_message;
6859  error_message
6860  << "The (" << is << ")-th segment has no elements\n";
6861  throw OomphLibError(error_message.str(),
6862  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6863  OOMPH_EXCEPTION_LOCATION);
6864  } // if (segment_sorted_ele_pt[is].size() == 0)
6865 #endif
6866 
6867  // Get access to the first element on the segment
6868  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6869 
6870  // Number of nodes
6871  const unsigned nnod = first_ele_pt->nnode();
6872 
6873  // Get the first node of the current segment
6874  Node *first_node_pt = first_ele_pt->node_pt(0);
6875  if (is_inverted[first_ele_pt])
6876  {
6877  first_node_pt = first_ele_pt->node_pt(nnod-1);
6878  }
6879 
6880  // Get access to the last element on the segment
6881  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
6882 
6883  // Get the last node of the current segment
6884  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
6885  if (is_inverted[last_ele_pt])
6886  {
6887  last_node_pt = last_ele_pt->node_pt(0);
6888  }
6889 
6890  // Coordinates of left node
6891  double x_left = first_node_pt->x(0);
6892  double y_left = first_node_pt->x(1);
6893 
6894  // Initialise boundary coordinate (local boundary coordinate for
6895  // boundaries with more than one segment)
6896  Vector<double> zeta(1, 0.0);
6897 
6898  // If we have associated a GeomObject then it is not necessary to
6899  // compute the arclength, only read the values from the nodes at
6900  // the edges
6901  if (this->boundary_geom_object_pt(b)!=0)
6902  {
6903  first_node_pt->get_coordinates_on_boundary(b, zeta);
6904  initial_zeta_segment[is] = zeta[0];
6905  last_node_pt->get_coordinates_on_boundary(b, zeta);
6906  final_zeta_segment[is] = zeta[0];
6907  }
6908 
6909  // Lexicographically bottom left node
6910  std::set<Node*> local_nodes_pt;
6911  local_nodes_pt.insert(first_node_pt);
6912 
6913  // Now loop over nodes in order
6914  for (std::list<FiniteElement*>::iterator it =
6915  segment_sorted_ele_pt[is].begin();
6916  it != segment_sorted_ele_pt[is].end(); it++)
6917  {
6918  // Get element
6919  FiniteElement* el_pt = *it;
6920 
6921  // Start node and increment
6922  unsigned k_nod = 1;
6923  int nod_diff = 1;
6924  if (is_inverted[el_pt])
6925  {
6926  k_nod = nnod - 2;
6927  nod_diff = -1;
6928  }
6929 
6930  // Loop over nodes
6931  for (unsigned j = 1; j < nnod; j++)
6932  {
6933  Node* nod_pt = el_pt->node_pt(k_nod);
6934  k_nod += nod_diff;
6935 
6936  // Coordinates of right node
6937  double x_right = nod_pt->x(0);
6938  double y_right = nod_pt->x(1);
6939 
6940  // Increment boundary coordinate
6941  zeta[0] += sqrt(
6942  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
6943  * (y_right - y_left));
6944 
6945  // Increment reference coordinate
6946  x_left = x_right;
6947  y_left = y_right;
6948 
6949  // Get lexicographically bottom left node but only
6950  // use vertex nodes as candidates
6951  local_nodes_pt.insert(nod_pt);
6952 
6953  } // for (j < nnod)
6954  } // iterator over the elements in the segment
6955 
6956  // Store the arclength of the segment
6957  segment_arclength[is] = zeta[0];
6958 
6959  // Add the nodes for the corresponding segment in the container
6960  segment_all_nodes_pt.push_back(local_nodes_pt);
6961 
6962  } // for (is < nsegments)
6963 
6964  // ------------------------------------------------------------------
6965  // Fourth: Now we have the segments sorted, with arclength and with
6966  // LOCAL arclength assigned to the nodes. Procced to re-scale the
6967  // coordinates on the nodes based on the arclength
6968  // ------------------------------------------------------------------
6969 
6970  // ------------------------------------------------------------------
6971  // Clear the original storages
6972  Boundary_segment_inverted[b].clear();
6973  Boundary_segment_initial_coordinate[b].clear();
6974  Boundary_segment_final_coordinate[b].clear();
6975 
6976  Boundary_segment_initial_zeta[b].clear();
6977  Boundary_segment_final_zeta[b].clear();
6978 
6979  Boundary_segment_initial_arclength[b].clear();
6980  Boundary_segment_final_arclength[b].clear();
6981 
6982  // Get the zeta values for the first and last node in the boundary
6983  Vector<double> first_node_zeta_coordinate(1,0.0);
6984  Vector<double> last_node_zeta_coordinate(1,0.0);
6985  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
6986  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
6987 
6988  // Get the boundary arclength
6989  const double boundary_arclength =
6990  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
6991 
6992  // Go through the segments and get the first and last node for each
6993  // segment
6994  for (unsigned is = 0; is < nsegments; is++)
6995  {
6996  // Get the first face element of the segment
6997  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
6998 
6999  // The number of nodes
7000  const unsigned nnod = first_face_ele_pt->nnode();
7001 
7002  // ... and the first node of the segment
7003  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7004  if (is_inverted[first_face_ele_pt])
7005  {
7006  first_node_pt = first_face_ele_pt->node_pt(nnod-1);
7007  }
7008 
7009  // Get the bound coordinates of the node
7010  Vector<double> zeta_first(1);
7011  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7012 
7013  // Get the last face element of the segment
7014  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7015 
7016  // ... and the last node of the segment
7017  Node* last_node_pt = last_face_ele_pt->node_pt(nnod-1);
7018  if (is_inverted[last_face_ele_pt])
7019  {
7020  last_node_pt = last_face_ele_pt->node_pt(0);
7021  }
7022 
7023  // Get the bound coordinates of the node
7024  Vector<double> zeta_last(1);
7025  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7026 
7027  // Now that we have the first and last node of the segment, get
7028  // the coordinates of the nodes
7029  Vector<double> first_node_coord(2);
7030  Vector<double> last_node_coord(2);
7031  for (unsigned i = 0; i < 2; i++)
7032  {
7033  first_node_coord[i] = first_node_pt->x(i);
7034  last_node_coord[i] = last_node_pt->x(i);
7035  }
7036 
7037  // Re-assign the values to identify the segments on the new mesh
7038  Boundary_segment_inverted[b].push_back(0);
7039  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7040  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7041 
7042  // Check if the boudary has an associated GeomObject
7043  if (this->boundary_geom_object_pt(b)!=0)
7044  {
7045  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7046  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7047  }
7048  else
7049  {
7050  // Re-assign the values and re-scale them
7051  Boundary_segment_initial_arclength[b].push_back(
7052  zeta_first[0] * boundary_arclength);
7053  Boundary_segment_final_arclength[b].push_back(
7054  zeta_last[0] * boundary_arclength);
7055  }
7056 
7057  } // for (is < nsegments)
7058 
7059  // Clean all the created face elements
7060  for (unsigned i = 0; i < nele; i++)
7061  {
7062  delete face_el_pt[i];
7063  face_el_pt[i] = 0;
7064  }
7065 
7066  }
7067 
7068 #endif // OOMPH_HAS_MPI
7069 
7070 
7071 
7072 #ifdef OOMPH_HAS_TRIANGLE_LIB
7073 
7074  //========================================================================
7075  /// Create TriangulateIO object via the .poly file
7076  //========================================================================
7077  template <class ELEMENT>
7079  build_triangulateio(const std::string& poly_file_name,
7080  TriangulateIO& triangulate_io,
7081  bool &use_attributes)
7082  {
7083 
7084  // Process poly file
7085  // -----------------
7086  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
7087  if(!poly_file)
7088  {
7089  throw OomphLibError("Error opening .poly file\n",
7090  OOMPH_CURRENT_FUNCTION,
7091  OOMPH_EXCEPTION_LOCATION);
7092  }
7093 
7094  // Initialize triangulateio structure
7095  TriangleHelper::initialise_triangulateio(triangulate_io);
7096 
7097  // Ignore the first line with structure description
7098  poly_file.ignore(80,'\n');
7099 
7100  // Read and store number of nodes
7101  unsigned invertices;
7102  poly_file>>invertices;
7103  triangulate_io.numberofpoints=invertices;
7104 
7105  // Initialisation of the point list
7106  triangulate_io.pointlist =
7107  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7108 
7109  // Read and store spatial dimension of nodes
7110  unsigned mesh_dim;
7111  poly_file>>mesh_dim;
7112 
7113  if(mesh_dim == 0)
7114  {
7115  mesh_dim=2;
7116  }
7117 
7118 #ifdef PARANOID
7119  if(mesh_dim!=2)
7120  {
7121  throw OomphLibError("The dimension must be 2\n",
7122  OOMPH_CURRENT_FUNCTION,
7123  OOMPH_EXCEPTION_LOCATION);
7124  }
7125 #endif
7126 
7127  // Read and check the flag for attributes
7128  unsigned nextras;
7129  poly_file>> nextras;
7130 
7131  triangulate_io.numberofpointattributes = 0;
7132  triangulate_io.pointattributelist = (double *) NULL;
7133 
7134  // Read and check the flag for boundary markers
7135  unsigned nodemarkers;
7136  poly_file>>nodemarkers;
7137  triangulate_io.pointmarkerlist = (int *) NULL;
7138 
7139 #ifdef PARANOID
7140  // Reading the .poly with the oomph.lib we need
7141  // to set the point attribute and markers to 0
7142  if(nextras!=0 || nodemarkers!=0)
7143  {
7144  oomph_info << "===================================================="
7145  << std::endl<<std::endl;
7146  oomph_info <<"Reading the .poly file via oomph_lib \n"
7147  <<"point's attribute and point's markers \n"
7148  <<"are automatically set to 0"<<std::endl;
7149  oomph_info << "===================================================="
7150  <<std::endl;
7151  }
7152 #endif
7153 
7154  // Dummy for node number (and attribute or markers if included)
7155  unsigned dummy_value;
7156  unsigned count_point=0;
7157  std::string test_string;
7158 
7159  // Skip line with commentary
7160  getline(poly_file,test_string,'#');
7161  poly_file.ignore(80,'\n');
7162 
7163  // Read and store all the nodes coordinates
7164  // (hole's vertices as well)
7165  for(unsigned count=0;count<invertices;count++)
7166  {
7167  poly_file>>dummy_value;
7168  poly_file>>triangulate_io.pointlist[count_point];
7169  poly_file>>triangulate_io.pointlist[count_point+1];
7170  if(nextras!=0 || nodemarkers!=0)
7171  {
7172  for(unsigned j=0;j<nextras;j++)
7173  {
7174  poly_file>>dummy_value;
7175  }
7176  }
7177  else if(nextras!=0 && nodemarkers!=0)
7178  {
7179  for(unsigned j=0;j<nextras;j++)
7180  {
7181  poly_file>>dummy_value;
7182  poly_file>>dummy_value;
7183  }
7184  }
7185  // Read the next line
7186  poly_file.ignore(80,'\n');
7187 
7188  // Skip line with commentary for internal box whether found
7189  if(poly_file.get() == '#')
7190  {
7191  poly_file.ignore(80,'\n');
7192  }
7193  // If read the char should be put back in the string
7194 
7195  else
7196  {
7197  poly_file.unget();
7198  }
7199  count_point+=2;
7200  }
7201 
7202  // The line with the segment's commentary has been skipped
7203  // by the command of the last loop
7204 
7205  // Read and store the number of segments
7206  unsigned dummy_seg;
7207  unsigned inelements;
7208  poly_file>>inelements;
7209 
7210  unsigned segment_markers;
7211  poly_file>>segment_markers;
7212 
7213  // Marker list should be provided by the user to assign
7214  // each segment to a boundary
7215 #ifdef PARANOID
7216  if(segment_markers!=1)
7217  {
7218 
7219  std::ostringstream error_stream;
7220  error_stream
7221  <<"The segment marker should be provided \n"
7222  <<"In order to assign each segment to a boundary \n "<< std::endl;
7223 
7224  throw OomphLibError(error_stream.str(),
7225  OOMPH_CURRENT_FUNCTION,
7226  OOMPH_EXCEPTION_LOCATION);
7227  }
7228 #endif
7229 
7230  triangulate_io.numberofsegments = inelements;
7231  triangulate_io.segmentlist =
7232  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7233  triangulate_io.segmentmarkerlist =
7234  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
7235 
7236  // Read all the segments edges and markers
7237  for(unsigned i=0;i<2*inelements;i+=2)
7238  {
7239  poly_file>>dummy_seg;
7240  poly_file>>triangulate_io.segmentlist[i];
7241  poly_file>>triangulate_io.segmentlist[i+1];
7242  if(segment_markers!=0)
7243  {
7244  poly_file>>triangulate_io.segmentmarkerlist[i/2];
7245  }
7246 
7247  //Skip line with commentary
7248  poly_file.ignore(80,'\n');
7249  }
7250 
7251  // Read and store the number of holes if given
7252  // Skip line with commentary
7253  if(getline(poly_file,test_string,'#'))
7254  {
7255  poly_file.ignore(80,'\n');
7256 
7257  unsigned dummy_hole;
7258  unsigned nhole;
7259  poly_file>>nhole;
7260 
7261  triangulate_io.numberofholes = nhole;
7262  triangulate_io.holelist =
7263  (double *) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7264 
7265  // Loop over the holes to get centre coords and store value onto the
7266  // TriangulateIO object
7267  for(unsigned i=0;i<2*nhole;i+=2)
7268  {
7269  poly_file>>dummy_hole;
7270  poly_file>>triangulate_io.holelist[i];
7271  poly_file>>triangulate_io.holelist[i+1];
7272  }
7273  }
7274 
7275  // Read and store the number of regions if given
7276  // Skip line with commentary
7277  if(getline(poly_file,test_string,'#'))
7278  {
7279  poly_file.ignore(80,'\n');
7280 
7281  unsigned dummy_region;
7282  unsigned nregion;
7283  poly_file>>nregion;
7284  std::cerr << "Regions: "<< nregion << std::endl;
7285  getchar();
7286 
7287  triangulate_io.numberofregions = nregion;
7288  triangulate_io.regionlist =
7289  (double *) malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7290 
7291  // Check for using regions
7292  if (nregion > 0)
7293  {use_attributes=true;}
7294 
7295  // Loop over the regions to get coords and store value onto the
7296  // TriangulateIO object
7297  for(unsigned i=0;i<nregion;i++)
7298  {
7299  poly_file>>dummy_region;
7300  poly_file>>triangulate_io.regionlist[4*i];
7301  poly_file>>triangulate_io.regionlist[4*i+1];
7302  poly_file>>triangulate_io.regionlist[4*i+2];
7303  triangulate_io.regionlist[4*i+3] = 0.0;
7304  }
7305  }
7306 
7307  }
7308 
7309 #endif
7310 
7311 #ifdef OOMPH_HAS_TRIANGLE_LIB
7312 #ifdef OOMPH_HAS_MPI
7313 
7314  //======================================================================
7315  /// Used to dump info. related with distributed triangle meshes
7316  //======================================================================
7317  template<class ELEMENT>
7319  dump_distributed_info_for_restart(std::ostream &dump_file)
7320  {
7321  // First check that the mesh is distributed
7322  if (this->is_mesh_distributed())
7323  {
7324  // Save the original number of boundaries
7325  const unsigned nboundary = this->nboundary();
7326  dump_file << nboundary
7327  << " # number of original boundaries" << std::endl;
7328 
7329  // Save the number of shared boundaries
7330  const unsigned nshared_boundaries = this->nshared_boundaries();
7331  dump_file << nshared_boundaries
7332  << " # number of shared boundaries" << std::endl;
7333 
7334  // Save the initial and final shared boundaries ids
7335  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7336  dump_file << init_shd_bnd_id
7337  << " # initial shared boundaries id" << std::endl;
7338 
7339  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7340  dump_file << final_shd_bnd_id
7341  << " # final shared boundaries id" << std::endl;
7342 
7343  // Save the number of processors
7344  const unsigned nprocs = this->shared_boundaries_ids().size();
7345  dump_file << nprocs << " # number of processors" << std::endl;
7346 
7347  // Now save the processors ids and the shared boundary created
7348  // by them
7349  for (unsigned ip = 0; ip < nprocs; ip++)
7350  {
7351  for (unsigned jp = 0; jp < nprocs; jp++)
7352  {
7353  if (ip != jp)
7354  {
7355  // Get the number of shared boundaries with it these two
7356  // processors
7357  const unsigned nshared_boundaries_iproc_jproc =
7358  this->shared_boundaries_ids(ip, jp).size();
7359 
7360  // Save the number of shared boundaries with in these two
7361  // processors
7362  dump_file << nshared_boundaries_iproc_jproc
7363  << " # number of shared boundaries with in two "
7364  << "processors" << std::endl;
7365  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7366  {
7367  const unsigned shared_boundary_id =
7368  this->shared_boundaries_ids(ip, jp, is);
7369  dump_file << ip << " " << jp << " " << shared_boundary_id
7370  << " # ip jp shared_boundary of processors ip and jp"
7371  << std::endl;
7372 
7373  } // for (is < nshared_boundaries_iproc_jproc)
7374  }
7375  } // for (jp < nprocs)
7376  } // for (ip < nprocs)
7377 
7378  // Now save the info. that states which shared boundary overlaps
7379  // an internal boundary
7380 
7381  // First check if there are shared boundaries overlapping internal
7382  // boundaries
7383  const unsigned nshared_boundaries_overlap_internal_boundaries =
7384  this->nshared_boundary_overlaps_internal_boundary();
7385  dump_file << nshared_boundaries_overlap_internal_boundaries
7386  << " # number of shared boundaries that overlap internal "
7387  << "boundaries" << std::endl;
7388 
7389  if (nshared_boundaries_overlap_internal_boundaries > 0)
7390  {
7391  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7392  {
7393  // Check if the current shared boundary overlaps an internal
7394  // boundary
7395  if (this->shared_boundary_overlaps_internal_boundary(isb))
7396  {
7397  // Which internal boundary is overlapped by the shared
7398  // boundary
7399  const unsigned overlapped_internal_boundary =
7400  shared_boundary_overlapping_internal_boundary(isb);
7401  // Save the shared boundary that overlaps the internal boundary
7402  dump_file << isb << " " << overlapped_internal_boundary
7403  << " # the shared boundary overlaps the internal "
7404  << "boundary " << std::endl;
7405 
7406  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7407  } // for (isb < final_shd_bnd_id)
7408  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7409 
7410  // Now save the info. related with the initial and final
7411  // boundary coordinates for each original boundary
7412 
7413  // Go through all the (original) boundaries to update the initial
7414  // and final boundary coordinates
7415  for (unsigned b = 0; b < nboundary; b++)
7416  {
7417  // Check if the boundary zeta coordinates for this boundary have
7418  // been already assigned, if that is the case then state the
7419  // flag to know that info. should be read
7420  if (Assigned_segments_initial_zeta_values[b])
7421  {
7422  // The boundary coordinates have been computed then state
7423  // the flag and save the info.
7424  dump_file << "1 # assigned boundary coordinates initial zeta values"
7425  << std::endl;
7426 
7427  // Save the initial and final boundary coordinates, same as
7428  // the initial and final zeta values for each boundary
7429 
7430  // First the vertices coordinates
7431  Vector<double> initial_coordinates=this->boundary_initial_coordinate(b);
7432 
7433  Vector<double> final_coordinates=this->boundary_final_coordinate(b);
7434 
7435  dump_file << std::setprecision(14)
7436  << initial_coordinates[0] << " " << initial_coordinates[1]
7437  << " # initial coordinates for the current boundary"
7438  << std::endl;
7439 
7440  dump_file << std::setprecision(14)
7441  << final_coordinates[0] << " " << final_coordinates[1]
7442  << " # final coordinates for the current boundary"
7443  << std::endl;
7444 
7445  // ... then the zeta values
7446 
7447 #ifdef PARANOID
7448  // Get the number of zeta coordinates (should be one)
7449  const unsigned zeta_size =
7450  this->boundary_initial_zeta_coordinate(b).size();
7451 
7452  if (zeta_size != 1)
7453  {
7454  std::ostringstream error_message;
7455  error_message
7456  <<"The dimension for the zeta values container is different\n"
7457  << "from 1, the current implementation only supports\n"
7458  << "one-dimensioned zeta containers\n\n";
7459  throw OomphLibError(error_message.str(),
7460  "TriangleMesh::dump_distributed_info_for_restart()",
7461  OOMPH_EXCEPTION_LOCATION);
7462  }
7463 #endif
7464 
7465  Vector<double> zeta_initial = this->boundary_initial_zeta_coordinate(b);
7466  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7467 
7468  dump_file << std::setprecision(14)
7469  << zeta_initial[0]
7470  << " # initial zeta value for the current boundary"
7471  << std::endl;
7472 
7473  dump_file << std::setprecision(14)
7474  << zeta_final[0]
7475  << " # final zeta value for the current boundary"
7476  << std::endl;
7477 
7478  // Get the number of segments of the current boundary
7479  const unsigned nsegments = this->nboundary_segment(b);
7480  // Save the number of segments of the current boundary
7481  dump_file << b << " " << nsegments
7482  << " # of segments for the current boundary"
7483  << std::endl;
7484 
7485  // ... and then save that info for each segments
7486  for (unsigned is = 0; is < nsegments; is++)
7487  {
7488  // First the vertices coordinates
7489  Vector<double> initial_segment_coordinates =
7490  this->boundary_segment_initial_coordinate(b)[is];
7491  Vector<double> final_segment_coordinates =
7492  this->boundary_segment_final_coordinate(b)[is];
7493 
7494  dump_file << std::setprecision(14)
7495  << initial_segment_coordinates[0] << " "
7496  << initial_segment_coordinates[1]
7497  << " # initial segment coordinates for the current boundary"
7498  << std::endl;
7499 
7500  dump_file << std::setprecision(14)
7501  << final_segment_coordinates[0] << " "
7502  << final_segment_coordinates[1]
7503  << " # final segment coordinates for the current boundary"
7504  << std::endl;
7505 
7506  // ... then the zeta values
7507 
7508  if (this->boundary_geom_object_pt(b)!=0)
7509  {
7510  const double zeta_segment_initial =
7511  this->boundary_segment_initial_zeta(b)[is];
7512  const double zeta_segment_final =
7513  this->boundary_segment_final_zeta(b)[is];
7514 
7515  dump_file << std::setprecision(14)
7516  << zeta_segment_initial
7517  << " # initial segment zeta value for the current boundary"
7518  << std::endl;
7519 
7520  dump_file << std::setprecision(14)
7521  << zeta_segment_final
7522  << " # final segment zeta value for the current boundary"
7523  << std::endl;
7524  }
7525  else
7526  {
7527  const double arclength_segment_initial =
7528  this->boundary_segment_initial_arclength(b)[is];
7529  const double arclength_segment_final =
7530  this->boundary_segment_final_arclength(b)[is];
7531 
7532  dump_file << std::setprecision(14)
7533  << arclength_segment_initial
7534  << " # initial segment arclength for the current boundary"
7535  << std::endl;
7536 
7537  dump_file << std::setprecision(14)
7538  << arclength_segment_final
7539  << " # final segment arclength for the current boundary"
7540  << std::endl;
7541 
7542  } // else if (this->boundary_geom_object_pt(b)!=0)
7543 
7544  } // for (is < nsegments)
7545 
7546  } // if (Assigned_segments_initial_zeta_values[b])
7547  else
7548  {
7549  // The boundary coordinates have NOT been computed then state
7550  // the flag and save the info.
7551  dump_file << "0 # assigned boundary coordinates initial zeta values"
7552  << std::endl;
7553  }
7554 
7555  } // for (b < nboundary)
7556 
7557  } // if (this->is_mesh_distributed())
7558 
7559  }
7560 
7561  //======================================================================
7562  /// Used to read info. related with distributed triangle meshes
7563  //======================================================================
7564  template<class ELEMENT>
7566  read_distributed_info_for_restart(std::istream &restart_file)
7567  {
7568  // First check that the mesh is distributed
7569  if (this->is_mesh_distributed())
7570  {
7571  // Read the number of original boundaries
7572  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7573 
7574 #ifdef PARANOID
7575  if (n_boundary != this->nboundary())
7576  {
7577  std::ostringstream error_message;
7578  error_message
7579  << "The number of boundaries (" << n_boundary << ") on the "
7580  << "file used for restarting is different\nfrom the number of "
7581  << "boundaries ("<< this->nboundary() << ") on the current "
7582  << "mesh!!!\n\n\n";
7583  throw OomphLibError(error_message.str(),
7584  "TriangleMesh::read_distributed_info_for_restart()",
7585  OOMPH_EXCEPTION_LOCATION);
7586  }
7587 #endif
7588 
7589  // Read the number of shared boundaries
7590  unsigned n_shared_boundaries =
7591  read_unsigned_line_helper(restart_file);
7592  // We need to read the data because it comes in the file (add and
7593  // substract to avoid compilation warning)
7594  n_shared_boundaries++;
7595  n_shared_boundaries--;
7596 
7597  // Read the initial and final shared boundaries ids
7598  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7599  // We need to read the data because it comes in the file (add and
7600  // substract to avoid compilation warning)
7601  init_shd_bnd_id++;
7602  init_shd_bnd_id--;
7603  // Add and substract to avoid compilation warning
7604  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7605  // We need to read the data because it comes in the file (add and
7606  // substract to avoid compilation warning)
7607  final_shd_bnd_id++;
7608  final_shd_bnd_id--;
7609 
7610  // Read the number of processors involved in the generation of
7611  // mesh before restart
7612  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7613 
7614 #ifdef PARANOID
7615  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7616  {
7617  std::ostringstream error_message;
7618  error_message
7619  << "The number of previously used processors ("<< n_procs
7620  << ") (read from the restart file) is different\nfrom the "
7621  << "number of current used processors ("
7622  << this->communicator_pt()->nproc() << ")\n\n";
7623  throw OomphLibError(error_message.str(),
7624  "TriangleMesh::read_distributed_info_for_restart()",
7625  OOMPH_EXCEPTION_LOCATION);
7626  }
7627 #endif
7628 
7629  // Clear all previuos info. related with shared boundaries
7630  this->shared_boundaries_ids().clear();
7631  this->shared_boundary_from_processors().clear();
7632  this->shared_boundary_overlaps_internal_boundary().clear();
7633 
7634  // Create the storage for the shared boundaries ids related with
7635  // the processors
7636  this->shared_boundaries_ids().resize(n_procs);
7637 
7638  // Now read the processors ids and the shared boundary created
7639  // by them
7640  for (unsigned ip = 0; ip < n_procs; ip++)
7641  {
7642  // Create the storage for the shared boundaries ids related with
7643  // the processors
7644  this->shared_boundaries_ids(ip).resize(n_procs);
7645  for (unsigned jp = 0; jp < n_procs; jp++)
7646  {
7647  if (ip != jp)
7648  {
7649  // Read the number of shared boundaries with in these two
7650  // processors
7651  const unsigned nshared_boundaries_iproc_jproc =
7652  read_unsigned_line_helper(restart_file);
7653  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7654  {
7655  // Get the processors
7656  unsigned tmp_ip;
7657  restart_file >> tmp_ip;
7658  unsigned tmp_jp;
7659  restart_file >> tmp_jp;
7660 
7661  // Get the shared boundary id created by these two
7662  // processors
7663  const unsigned shared_boundary_id =
7664  read_unsigned_line_helper(restart_file);
7665 
7666  // Update the info. of the processors that give rise to
7667  // the shared boundaries
7668  this->shared_boundaries_ids(ip, jp).
7669  push_back(shared_boundary_id);
7670 
7671  // Update the structure that states the processors that
7672  // gave rise to the shared boundary
7673  Vector<unsigned> processors(2);
7674  processors[0] = ip;
7675  processors[1] = jp;
7676  this->shared_boundary_from_processors()[shared_boundary_id] =
7677  processors;
7678 
7679  } // for (is < nshared_boundaries_iproc_jproc)
7680  }
7681  } // for (jp < n_procs)
7682  } // for (ip < n_procs)
7683 
7684  // Now read the info. that states which shared boundary overlaps
7685  // an internal boundary
7686 
7687  // First check if there are shared boundaries overlapping internal
7688  // boundaries
7689  const unsigned nshared_boundaries_overlap_internal_boundaries =
7690  read_unsigned_line_helper(restart_file);
7691 
7692  for (unsigned isb = 0;
7693  isb < nshared_boundaries_overlap_internal_boundaries;
7694  isb++)
7695  {
7696  // Read the shared boundary that overlaps an internal boundary
7697  unsigned shared_boundary_overlapping;
7698  restart_file >> shared_boundary_overlapping;
7699  // ... and read the internal boundary that overlaps
7700  const unsigned overlapped_internal_boundary =
7701  read_unsigned_line_helper(restart_file);
7702 
7703  // Re-establish the info. of the shared boundaries overlapped
7704  // by internal boundaries
7705  this->shared_boundary_overlaps_internal_boundary()
7706  [shared_boundary_overlapping] = overlapped_internal_boundary;
7707  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7708 
7709  // Now read the info. related with the initial and final
7710  // boundary coordinates for each original boundary
7711 
7712  // Go through all the (original) boundaries to update the initial
7713  // and final boundary coordinates
7714  for (unsigned b = 0; b < n_boundary; b++)
7715  {
7716  // For each boundary check if the boundary coordinates initial
7717  // and final zeta vales were assigned in the restart file
7718  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7719  read_unsigned_line_helper(restart_file);
7720 
7721  if (boundary_coordinates_initial_zeta_values_assigned)
7722  {
7723  // Clear any previous stored info. There should not be
7724  // info. already stored but better clear the info. for the
7725  // boundary
7726  Boundary_initial_coordinate[b].clear();
7727  Boundary_final_coordinate[b].clear();
7728 
7729  Boundary_initial_zeta_coordinate[b].clear();
7730  Boundary_final_zeta_coordinate[b].clear();
7731 
7732  // The info. for the segments
7733  Boundary_segment_inverted[b].clear();
7734  Boundary_segment_initial_coordinate[b].clear();
7735  Boundary_segment_final_coordinate[b].clear();
7736 
7737  Boundary_segment_initial_zeta[b].clear();
7738  Boundary_segment_final_zeta[b].clear();
7739 
7740  Boundary_segment_initial_arclength[b].clear();
7741  Boundary_segment_final_arclength[b].clear();
7742 
7743  // Read the initial and final boundary coordinates, same as
7744  // the initial and final zeta values for each boundary
7745 
7746  // First the vertices coordinates
7747  Vector<double> initial_coordinates(2);
7748 
7749  // Read the initial coordinates
7750  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7751 
7752  // Ignore rest of line
7753  restart_file.ignore(80,'\n');
7754 
7755  Vector<double> final_coordinates(2);
7756 
7757  // Read the final coordinates
7758  restart_file >> final_coordinates[0] >> final_coordinates[1];
7759 
7760  // Ignore rest of line
7761  restart_file.ignore(80,'\n');
7762 
7763  // Set the values in the containers
7764 
7765 
7766  this->boundary_initial_coordinate(b)=initial_coordinates;
7767  this->boundary_final_coordinate(b)=final_coordinates;
7768 
7769  // ... now read the zeta values
7770  Vector<double> zeta_initial(1);
7771  restart_file >> zeta_initial[0];
7772 
7773  // Ignore rest of line
7774  restart_file.ignore(80,'\n');
7775 
7776  Vector<double> zeta_final(1);
7777  restart_file >> zeta_final[0];
7778 
7779  // Ignore rest of line
7780  restart_file.ignore(80,'\n');
7781 
7782  // Set the values in the containers
7783  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7784  this->boundary_final_zeta_coordinate(b) = zeta_final;
7785 
7786  // Get the curent boundary id from the restart file
7787  unsigned current_boundary;
7788  restart_file >> current_boundary;
7789 
7790 #ifdef PARANOID
7791  if (current_boundary != b)
7792  {
7793  std::ostringstream error_message;
7794  error_message
7795  << "The current boundary id from the restart file ("
7796  << current_boundary << ") is different from\nthe boundary id "
7797  << b << "currently used to re-establish the initial and\nfinal "
7798  << "segment's zeta values\n\n";
7799  throw OomphLibError(error_message.str(),
7800  "TriangleMesh::read_distributed_info_for_restart()",
7801  OOMPH_EXCEPTION_LOCATION);
7802  }
7803 #endif
7804 
7805  // ... and its number of segments
7806  unsigned nsegments;
7807  restart_file >> nsegments;
7808 
7809  // Ignore rest of line
7810  restart_file.ignore(80,'\n');
7811 
7812  // Now read all the segments info.
7813 
7814  // ... and then save that info for each segments
7815  for (unsigned is = 0; is < nsegments; is++)
7816  {
7817  // First the vertices coordinates
7818  Vector<double> initial_segment_coordinates(2);
7819 
7820  // Read the initial coordinates
7821  restart_file >> initial_segment_coordinates[0]
7822  >> initial_segment_coordinates[1];
7823 
7824  // Ignore rest of line
7825  restart_file.ignore(80,'\n');
7826 
7827  Vector<double> final_segment_coordinates(2);
7828 
7829  // Read the final coordinates
7830  restart_file >> final_segment_coordinates[0]
7831  >> final_segment_coordinates[1];
7832 
7833  // Ignore rest of line
7834  restart_file.ignore(80,'\n');
7835 
7836  // Set the values in the containers
7837  this->boundary_segment_initial_coordinate(b).push_back(
7838  initial_segment_coordinates);
7839  this->boundary_segment_final_coordinate(b).push_back(
7840  final_segment_coordinates);
7841 
7842  // ... then the zeta values for the segment
7843  if (this->boundary_geom_object_pt(b)!=0)
7844  {
7845  Vector<double> zeta_segment_initial(1);
7846  restart_file >> zeta_segment_initial[0];
7847 
7848  // Ignore rest of line
7849  restart_file.ignore(80,'\n');
7850 
7851  Vector<double> zeta_segment_final(1);
7852  restart_file >> zeta_segment_final[0];
7853 
7854  // Ignore rest of line
7855  restart_file.ignore(80,'\n');
7856 
7857  // Set the values in the containers for the segment
7858  this->boundary_segment_initial_zeta(b).push_back(
7859  zeta_segment_initial[0]);
7860  this->boundary_segment_final_zeta(b).push_back(
7861  zeta_segment_final[0]);
7862  }
7863  else
7864  {
7865  Vector<double> arclength_segment_initial(1);
7866  restart_file >> arclength_segment_initial[0];
7867 
7868  // Ignore rest of line
7869  restart_file.ignore(80,'\n');
7870 
7871  Vector<double> arclength_segment_final(1);
7872  restart_file >> arclength_segment_final[0];
7873 
7874  // Ignore rest of line
7875  restart_file.ignore(80,'\n');
7876 
7877  // Set the values in the containers for the segment
7878  this->boundary_segment_initial_arclength(b).push_back(
7879  arclength_segment_initial[0]);
7880  this->boundary_segment_final_arclength(b).push_back(
7881  arclength_segment_final[0]);
7882  } // else if (this->boundary_geom_object_pt(b)!=0)
7883 
7884  } // for (is < nsegments)
7885 
7886  } // if (boundary_coordinates_initial_zeta_values_assigned)
7887 
7888  } // for (b < n_boundary)
7889 
7890  } // if (this->is_mesh_distributed())
7891 
7892  }
7893 
7894 #endif // #ifdef OOMPH_HAS_MPI
7895 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
7896 
7897  //===================================================================
7898  // Output the nodes on the boundaries and their / respective boundary
7899  // coordinates(into separate tecplot / zones)
7900  //===================================================================
7901  template<class ELEMENT>
7903  std::ostream &outfile)
7904  {
7905  // First get all the elements adjacent to the given boundary, then
7906  // the face elements and extract the nodes on the boundaries using
7907  // the face elements. We can not use the data structure
7908  // Boundary_node_pt since the multi_domain functions add nodes there
7909  // without assigning the required boundary coordinate
7910 
7911  // Store the nodes in a set so we do not have repeated nodes
7912  std::set<Node*> boundary_nodes_pt;
7913  const unsigned n_boundary_ele = this->nboundary_element(b);
7914  for (unsigned e = 0; e < n_boundary_ele; e++)
7915  {
7916  // Get the boundary bulk element
7917  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
7918 #ifdef OOMPH_HAS_MPI
7919  // Only work with nonhalo elements if the mesh is distributed
7920  if (!bulk_ele_pt->is_halo())
7921  {
7922 #endif
7923  // Get the face index
7924  int face_index = this->face_index_at_boundary(b, e);
7925  // Create the face element
7926  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
7927  bulk_ele_pt, face_index);
7928 
7929  // Get the number of nodes on the face element
7930  const unsigned n_nodes = face_ele_pt->nnode();
7931  for (unsigned i = 0; i < n_nodes; i++)
7932  {
7933  // Get the nodes in the face elements
7934  Node* tmp_node_pt = face_ele_pt->node_pt(i);
7935  // Add the nodes to the set of boundary nodes
7936  boundary_nodes_pt.insert(tmp_node_pt);
7937  } // for (i < n_nodes)
7938 
7939  // Free the memory allocated for the face element
7940  delete face_ele_pt;
7941  face_ele_pt = 0;
7942 #ifdef OOMPH_HAS_MPI
7943  } // if (!bulk_ele_pt->is_halo())
7944 #endif
7945 
7946  } // for (e < n_boundary_ele)
7947 
7948  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
7949  // Set to store the boundary nodes in order
7950  std::set<Vector<double> > set_node_coord;
7951  // Loop over the nodes on the boundary and store them in the set
7952  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
7953  it != boundary_nodes_pt.end(); it++)
7954  {
7955  Node *inode_pt = (*it);
7956 
7957  // Get the node coordinates
7958  const unsigned n_dim = inode_pt->ndim();
7959  Vector<double> node_coord(n_dim+1);
7960 
7961  // Get the boundary coordinate
7962  Vector<double> zeta(1);
7963  inode_pt->get_coordinates_on_boundary(b, zeta);
7964  node_coord[0] = zeta[0];
7965  for (unsigned j = 0; j < n_dim; j++)
7966  {
7967  node_coord[j+1] = inode_pt->x(j);
7968  }
7969  set_node_coord.insert(node_coord);
7970  }
7971 
7972  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7973  it != set_node_coord.end(); it++)
7974  {
7975  // Get the node coordinates
7976  Vector<double> node_coord = (*it);
7977 
7978  // Output the node coordinates
7979  const unsigned n_dim = node_coord.size()-1;
7980  for (unsigned j = 0; j < n_dim; j++)
7981  {
7982  outfile << node_coord[j+1] << " ";
7983  }
7984  // ... add an extra coordinate to avoid error with tecplot
7985  outfile << "0.0" << std::endl;
7986  }
7987 
7988  // ... loop again to plot the bound coordinates
7989  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
7990  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7991  it != set_node_coord.end(); it++)
7992  {
7993  // Get the node coordinates
7994  Vector<double> node_coord = (*it);
7995 
7996  // Output the node coordinates
7997  const unsigned n_dim = node_coord.size()-1;
7998  for (unsigned j = 0; j < n_dim; j++)
7999  {
8000  outfile << node_coord[j+1] << " ";
8001  }
8002 
8003  // Output the boundary coordinate
8004  outfile << node_coord[0] << std::endl;
8005  }
8006 
8007  }
8008 
8009 #ifdef OOMPH_HAS_MPI
8010  //====================================================================
8011  // \short Creates the distributed domain representation. Joins the
8012  // original boundaires, shared boundaries and creates connections among
8013  // them to create the new polygons that represent the distributed
8014  // domain
8015  //====================================================================
8016  template<class ELEMENT>
8018  Vector<TriangleMeshPolygon *> &polygons_pt,
8019  Vector<TriangleMeshOpenCurve*> &open_curves_pt)
8020  {
8021  // Get the outer polygons, internal polygons, internal open curves
8022  // and join them with the shared polylines to create the distributed
8023  // domain representation (the new outer, internal polygons, and new
8024  // internal open curves)
8025 
8026  // Get the rank of the current processor
8027  const unsigned my_rank = this->communicator_pt()->my_rank();
8028 
8029  // *********************************************************************
8030  // Step (2) Get the outer, internal and shared boundaries to create the
8031  // new polygons
8032  // *********************************************************************
8033 
8034  // *********************************************************************
8035  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8036  // a new representation (for example when the boundary was splitted in
8037  // the distribution process)
8038  // *********************************************************************
8039 
8040  // Storage for new created polylines, non sorted
8041  Vector<TriangleMeshPolyLine *> unsorted_outer_polyline_pt;
8042 
8043  // Storing for the polylines on the boundaries
8044  // The first index is for a set of connected polylines
8045  // The second index is for a polyline on a set of connected polylines
8046  Vector<Vector<TriangleMeshPolyLine *> > sorted_outer_curves_pt;
8047 
8048  // Copy the outer boundaries to the vector of polylines
8049  const unsigned nouter=this->Outer_boundary_pt.size();
8050  for (unsigned i = 0; i < nouter; i++)
8051  {
8052  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8053  for (unsigned p = 0; p < npolylines; p++)
8054  {
8055  // Pointer to the current polyline
8056  TriangleMeshPolyLine *tmp_polyline_pt =
8057  this->Outer_boundary_pt[i]->polyline_pt(p);
8058  const unsigned nvertex = tmp_polyline_pt->nvertex();
8059  if (nvertex > 0)
8060  {
8061  // Get the boundary id of the polyline and check if that boundary
8062  // needs a new representation (for example when the boundary was
8063  // splitted in the distribution process)
8064  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8065  if (!boundary_was_splitted(bound_id))
8066  {
8067  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8068  } // if (!boundary_was_splitted(bound_id))
8069  else
8070  {
8071  // Get the polylines that will represent this boundary
8072  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8073  boundary_subpolylines(bound_id);
8074  const unsigned nsub_poly = tmp_vector_polylines.size();
8075 #ifdef PARANOID
8076  if (nsub_poly <= 1)
8077  {
8078  std::ostringstream error_message;
8079  error_message
8080  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8081  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8082  throw OomphLibError(error_message.str(),
8083  OOMPH_CURRENT_FUNCTION,
8084  OOMPH_EXCEPTION_LOCATION);
8085  }
8086 #endif
8087  // Add the new representation of the polylines (sub-polylines)
8088  // to represent this boundary
8089  for (unsigned isub = 0; isub < nsub_poly; isub++)
8090  {
8091  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8092 #ifdef PARANOID
8093  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8094  if (nsvertex == 0)
8095  {
8096  std::ostringstream error_message;
8097  error_message
8098  << "The current chunk ("<< isub <<") of the polyline with\n"
8099  << "boundary id (" << bound_id << ") has no vertices\n";
8100  throw OomphLibError(error_message.str(),
8101  OOMPH_CURRENT_FUNCTION,
8102  OOMPH_EXCEPTION_LOCATION);
8103  } // if (nsvertex == 0)
8104 #endif // #ifdef PARANOID
8105  } // for (isub < nsub_poly)
8106  } // else if (!boundary_was_splitted(bound_id))
8107  } // if (nvertex > 0)
8108  } // for (p < npolylines)
8109  } // for (i < nouter)
8110 
8111  // Get the number of unsorted polylines
8112  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8113  if (nunsorted_outer_polyline > 0)
8114  {
8115 
8116  // Now that we have all the new unsorted polylines it is time to sort them
8117  // so they be all contiguous
8118  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8119 
8120  } // if (nunsorted_outer_polyline > 0)
8121 
8122  // *********************************************************************
8123  // Step (2.2) Get the internal closed boundaries and check if it is
8124  // necessary to use a new representation (for example when the boundary
8125  // was splitted in the distribution process)
8126  // *********************************************************************
8127 
8128  // Storage for new created polylines, non sorted
8129  Vector<TriangleMeshPolyLine *> unsorted_internal_closed_polyline_pt;
8130 
8131  // Storing for the polylines on the boundaries
8132  // The first index is for a set of connected polylines
8133  // The second index is for a polyline on a set of connected polylines
8134  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_closed_curves_pt;
8135 
8136  // Copy the internal closed boundaries to the vector of polylines
8137  const unsigned ninternal_closed=this->Internal_polygon_pt.size();
8138  for (unsigned i = 0; i < ninternal_closed; i++)
8139  {
8140  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8141  for (unsigned p = 0; p < npolylines; p++)
8142  {
8143  // Pointer to the current polyline
8144  TriangleMeshPolyLine *tmp_polyline_pt =
8145  this->Internal_polygon_pt[i]->polyline_pt(p);
8146  const unsigned nvertex = tmp_polyline_pt->nvertex();
8147  if (nvertex > 0)
8148  {
8149  // Get the boundary id of the polyline and check if that boundary
8150  // needs a new representation (for example when the boundary was
8151  // splitted in the distribution process)
8152  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8153  if (!boundary_was_splitted(bound_id))
8154  {
8155  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8156  } // if (!boundary_was_splitted(bound_id))
8157  else
8158  {
8159  // Get the polylines that will represent this boundary
8160  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8161  boundary_subpolylines(bound_id);
8162  const unsigned nsub_poly = tmp_vector_polylines.size();
8163 #ifdef PARANOID
8164  if (nsub_poly <= 1)
8165  {
8166  std::ostringstream error_message;
8167  error_message
8168  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8169  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8170  throw OomphLibError(error_message.str(),
8171  OOMPH_CURRENT_FUNCTION,
8172  OOMPH_EXCEPTION_LOCATION);
8173  }
8174 #endif
8175  // Add the new representation of the polylines (sub-polylines)
8176  // to represent this boundary
8177  for (unsigned isub = 0; isub < nsub_poly; isub++)
8178  {
8179  unsorted_internal_closed_polyline_pt.push_back(tmp_vector_polylines[isub]);
8180 #ifdef PARANOID
8181  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8182  if (nsvertex == 0)
8183  {
8184  std::ostringstream error_message;
8185  error_message
8186  << "The current chunk ("<< isub <<") of the polyline with\n"
8187  << "boundary id (" << bound_id << ") has no vertices\n";
8188  throw OomphLibError(error_message.str(),
8189  OOMPH_CURRENT_FUNCTION,
8190  OOMPH_EXCEPTION_LOCATION);
8191  } // if (nsvertex == 0)
8192 #endif // #ifdef PARANOID
8193  } // for (isub < nsub_poly)
8194  } // else if (!boundary_was_splitted(bound_id))
8195  } // if (nvertex > 0)
8196  } // for (p < npolylines)
8197  } // for (i < ninternal_closed)
8198 
8199  const unsigned nunsorted_internal_closed_polyline =
8200  unsorted_internal_closed_polyline_pt.size();
8201 
8202  if (nunsorted_internal_closed_polyline > 0)
8203  {
8204  // Now that we have all the new unsorted polylines it is time to sort them
8205  // so they be all contiguous
8206  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8207  sorted_internal_closed_curves_pt);
8208  }
8209 
8210  // *********************************************************************
8211  // Step (2.3) Get the internal open boundaries and check if it is
8212  // necessary to use a new representation (for example when the boundary
8213  // was splitted in the distribution process)
8214  // *********************************************************************
8215 
8216  // Storage for new created polylines, non sorted
8217  Vector<TriangleMeshPolyLine *> unsorted_internal_open_polyline_pt;
8218 
8219  // Storing for the polylines on the boundaries
8220  // The first index is for a set of connected polylines
8221  // The second index is for a polyline on a set of connected polylines
8222  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_open_curves_pt;
8223 
8224  // Copy the internal open boundaries to the vector of polylines
8225  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8226  for (unsigned i = 0; i < ninternal_open; i++)
8227  {
8228  const unsigned ncurve_section =
8229  this->Internal_open_curve_pt[i]->ncurve_section();
8230  for (unsigned p = 0; p < ncurve_section; p++)
8231  {
8232  // Pointer to the current polyline
8233  TriangleMeshPolyLine *tmp_polyline_pt =
8234  this->Internal_open_curve_pt[i]->polyline_pt(p);
8235  const unsigned nvertex = tmp_polyline_pt->nvertex();
8236  if (nvertex > 0)
8237  {
8238  // Get the boundary id of the polyline and check if that boundary
8239  // needs a new representation (for example when the boundary was
8240  // splitted in the distribution process)
8241  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8242  if (!boundary_was_splitted(bound_id))
8243  {
8244  // Only include as internal boundaries those not marked as
8245  // shared boundaries
8246  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8247  {
8248  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8249  }
8250  } // if (!boundary_was_splitted(bound_id))
8251  else
8252  {
8253  // Get the polylines that will represent this boundary
8254  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8255  boundary_subpolylines(bound_id);
8256  const unsigned nsub_poly = tmp_vector_polylines.size();
8257 #ifdef PARANOID
8258  if (nsub_poly <= 1)
8259  {
8260  std::ostringstream error_message;
8261  error_message
8262  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8263  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8264  throw OomphLibError(error_message.str(),
8265  OOMPH_CURRENT_FUNCTION,
8266  OOMPH_EXCEPTION_LOCATION);
8267  }
8268 #endif
8269  // Add the new representation of the polylines (sub-polylines)
8270  // to represent this boundary
8271  for (unsigned isub = 0; isub < nsub_poly; isub++)
8272  {
8273  // Only include as internal boundaries those not marked as
8274  // shared boundaries
8275  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8276  {
8277  unsorted_internal_open_polyline_pt.push_back(tmp_vector_polylines[isub]);
8278  }
8279 #ifdef PARANOID
8280  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8281  if (nsvertex == 0)
8282  {
8283  std::ostringstream error_message;
8284  error_message
8285  << "The current chunk ("<< isub <<") of the polyline with\n"
8286  << "boundary id (" << bound_id << ") has no vertices\n";
8287  throw OomphLibError(error_message.str(),
8288  OOMPH_CURRENT_FUNCTION,
8289  OOMPH_EXCEPTION_LOCATION);
8290  } // if (nsvertex == 0)
8291 #endif // #ifdef PARANOID
8292  } // for (isub < nsub_poly)
8293  } // else if (!boundary_was_splitted(bound_id))
8294  } // if (nvertex > 0)
8295  } // for (p < npolylines)
8296  } // for (i < ninternal_open)
8297 
8298  const unsigned nunsorted_internal_open_polyline =
8299  unsorted_internal_open_polyline_pt.size();
8300 
8301  if (nunsorted_internal_open_polyline > 0)
8302  {
8303  // Now that we have all the new unsorted polylines it is time to sort them
8304  // so they be all contiguous
8305  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8306  sorted_internal_open_curves_pt);
8307  }
8308 
8309  // ********************************************************************
8310  // Step (2.4) Sort the polylines on the shared boundaries
8311  // ********************************************************************
8312 
8313  // Storage for new created polylines, non sorted
8314  Vector<TriangleMeshPolyLine *> unsorted_shared_polyline_pt;
8315 
8316  // Special storage for the shared polylines that will be also used
8317  // to connect with the internal boundaries
8318  Vector<TriangleMeshPolyLine *> unsorted_shared_to_internal_polyline_pt;
8319 
8320  // Storing for the polylines on the shared boundaries
8321  // The first index is for a set of connected polylines
8322  // The second index is for a polyline on a set of connected polylines
8323  Vector<Vector<TriangleMeshPolyLine *> > sorted_shared_curves_pt;
8324 
8325  // Copy the shared boudaries to the vector of polylines
8326  const unsigned ncurves = nshared_boundary_curves(my_rank);
8327  for (unsigned i = 0; i < ncurves; i++)
8328  {
8329  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8330  for (unsigned p = 0; p < npolylines; p++)
8331  {
8332  const unsigned nvertex =
8333  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8334  if (nvertex > 0)
8335  {
8336  TriangleMeshPolyLine *tmp_shared_poly_pt =
8337  shared_boundary_polyline_pt(my_rank, i, p);
8338 
8339  // First check if there are shared boundaries overlapping
8340  // internal boundaries
8341  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8342  {
8343  // Get the boundary id of the shared polyline
8344  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8345  // If the shared polyline is marked as internal boundary
8346  // then include it in the special storage to look for
8347  // connection with internal boundaries
8348  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8349  {
8350  unsorted_shared_to_internal_polyline_pt.push_back(
8351  tmp_shared_poly_pt);
8352  }
8353  }
8354  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8355  }
8356  }
8357  }
8358 
8359  // Get the total number of shared polylines
8360  const unsigned nunsorted_shared_polyline =
8361  unsorted_shared_polyline_pt.size();
8362 
8363  if (nunsorted_shared_polyline > 0)
8364  {
8365  // Now that we have all the new unsorted polylines it is time to
8366  // sort them so they be all contiguous
8367  sort_polylines_helper(unsorted_shared_polyline_pt, sorted_shared_curves_pt);
8368  }
8369 
8370  // ********************************************************************
8371  // Step (3) Join the boundaries (shared, internal and outer to
8372  // create the new polygons)
8373  // ********************************************************************
8374 
8375  // Create the set of curves that will be used to create the new polygons
8376  // Get the total number of curves
8377  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8378  const unsigned ninternal_closed_curves =
8379  sorted_internal_closed_curves_pt.size();
8380  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8381  const unsigned ntotal_curves = nouter_curves +
8382  ninternal_closed_curves +
8383  nshared_curves;
8384 
8385  // Add all the polylines to a container
8386  unsigned counter = 0;
8387  Vector<Vector<TriangleMeshPolyLine *> > all_curves_pt(ntotal_curves);
8388 
8389  // Add the shared curves first, this ensure the generation of
8390  // internal polygons defined by the shared boundaries
8391  for (unsigned i = 0; i < nshared_curves; i++,counter++)
8392  {
8393  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8394  }
8395 
8396  // Add the internal polygons (if any)
8397  for (unsigned i = 0; i < ninternal_closed_curves; i++,counter++)
8398  {
8399  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8400  }
8401 
8402  // Add the outer polygons
8403  for (unsigned i = 0; i < nouter_curves; i++,counter++)
8404  {
8405  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8406  }
8407 
8408  // Create the temporary version of the domain by joining the new
8409  // polylines
8410  this->create_tmp_polygons_helper(all_curves_pt,polygons_pt);
8411  // Create the new open curves
8412  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8413  unsorted_shared_to_internal_polyline_pt,
8414  open_curves_pt);
8415 
8416  // ********************************************************************
8417  // Step (4) Create connections among the outer boundaries
8418  // (intersections with themselves)
8419  // ********************************************************************
8420 
8421  // After creating the new boundaries representation (polylines)
8422  // establish the connections of the shared boundaries (with
8423  // themselves or with the original boundaries). This avoids the
8424  // multiple definition of vertices in the domain which cause
8425  // problems when calling Triangle
8426 
8427  this->create_shared_polylines_connections();
8428 
8429  // ------------------------------------------------------------------
8430  // Compute the new holes information. Those from the
8431  // extra_holes_coordinates container, and those from the original
8432  // closed boundaries. Add the holes created by the halo elements
8433  // adjacent to the shared boundaries
8434 
8435  // The storage for the new holes, get those from the
8436  // extra_holes_coordinates container and those from the internal
8437  // closed boundaries that are defined as holes
8438  Vector<Vector<double> > new_holes_coordinates;
8439 
8440  // Copy the holes (those defined by the original internal closed
8441  // boundaries and those in the extra holes container)
8442 
8443  // The holes defined by the original internal closed boundaries
8444  const unsigned n_holes = this->Internal_polygon_pt.size();
8445  for (unsigned h = 0; h < n_holes; h++)
8446  {
8447  Vector<double> hole_coordinates =
8448  this->Internal_polygon_pt[h]->internal_point();
8449  // If the closed boundary is a hole, then copy its hole
8450  if (!hole_coordinates.empty())
8451  {
8452  new_holes_coordinates.push_back(hole_coordinates);
8453  }
8454  } // for (h < n_holes)
8455 
8456  // Is this the first time we are going to copy the extra holes
8457  // coordinates
8458  if (First_time_compute_holes_left_by_halo_elements)
8459  {
8460  // The holes in the extra holes container
8461  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8462  for (unsigned h = 0; h < n_extra_holes; h++)
8463  {
8464  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8465  new_holes_coordinates.push_back(hole_coordinates);
8466  } // for (h < n_extra_holes)
8467 
8468  // Copy the extra holes coordinates
8469  Original_extra_holes_coordinates = Extra_holes_coordinates;
8470 
8471  // Set the flag to false
8472  First_time_compute_holes_left_by_halo_elements = false;
8473 
8474  } // if (First_time_compute_holes_left_by_halo_elements)
8475  else
8476  {
8477  // Not the first time, then only copy the original extra holes
8478  // coordinates
8479  const unsigned n_original_extra_holes =
8480  Original_extra_holes_coordinates.size();
8481  for (unsigned h = 0; h < n_original_extra_holes; h++)
8482  {
8483  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8484  new_holes_coordinates.push_back(hole_coordinates);
8485  } // for (h < n_original_extra_holes)
8486  }
8487 
8488  // Add the holes created by the halo elements adjacent to the shared
8489  // boundaries
8490  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8491 
8492  // Update the holes information, only use the coordinate inside the
8493  // poylgons that define the new domain
8494  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8495 
8496  // tachidok Clear the storage by now
8497  //new_holes_coordinates.clear();
8498 
8499  // Now copy the info. in the extra holes coordinates container
8500  Extra_holes_coordinates = new_holes_coordinates;
8501 
8502  // Do not delete halo(ed) info., this will be "deleted"
8503  // automatically by not passing that information to the new adapted
8504  // mesh. Once the transfer of target areas is performed the halo(ed)
8505  // information is no longer required
8506 
8507  }
8508 
8509  //======================================================================
8510  // \short Take the polylines from the shared boundaries and the boundaries
8511  // to create polygons
8512  //======================================================================
8513  template<class ELEMENT>
8515  create_tmp_polygons_helper(Vector<Vector<TriangleMeshPolyLine *> >
8516  &polylines_pt,
8517  Vector<TriangleMeshPolygon *> &polygons_pt)
8518  {
8519  // Each vector of polylines (curve) is already sorted, it means that
8520  // all the polylines on the vector polylines_pt[i] point to the same
8521  // direction
8522 
8523  // --- Using this fact we should compare the first and last points from
8524  // these arrays of polylines (curves) and compare with the others
8525  // vectors of polylines (curves) end points
8526  // --- Once created a closed curve create a polygon
8527 
8528  // The number of curves
8529  const unsigned ncurves = polylines_pt.size();
8530 
8531  // The number of non sorted curves
8532  const unsigned nunsorted_curves = ncurves;
8533  // The number of sorted curves
8534  unsigned nsorted_curves = 0;
8535 
8536  // Vector to know which ncurve is already done
8537  std::vector<bool> done_curve(ncurves);
8538 
8539  do
8540  {
8541  // The list where to add the curves so that they be contiguous
8542  std::list<Vector<TriangleMeshPolyLine*> > list_building_polygon_pt;
8543 #ifdef PARANOID
8544  // Flag to indicate that a root curve was found
8545  bool root_curve_found = false;
8546 #endif
8547 
8548  // The index for the root_curve (we use it in further iterations as the
8549  // starting index so we dont need to search in already done curves)
8550  unsigned root_curve_idx = 0;
8551 
8552  // Get the root curve
8553  for (unsigned ic = 0; ic < ncurves; ic++)
8554  {
8555  if (!done_curve[ic])
8556  {
8557  root_curve_idx = ic;
8558  nsorted_curves++;
8559 #ifdef PARANOID
8560  root_curve_found = true;
8561 #endif
8562  done_curve[ic] = true;
8563  // ... break the loop
8564  break;
8565  }
8566  }
8567 
8568 #ifdef PARANOID
8569  if (!root_curve_found)
8570  {
8571  std::stringstream err;
8572  err <<"The root curve to create a polygon from the shared and "
8573  <<"original boundaries was not found!!!\n";
8574  throw OomphLibError(err.str(),
8575  "TriangleMesh::create_tmp_polygons_helper()",
8576  OOMPH_EXCEPTION_LOCATION);
8577  }
8578 #endif
8579 
8580  // Get the root curve
8581  Vector<TriangleMeshPolyLine*> root_curve_pt=polylines_pt[root_curve_idx];
8582 
8583  // Add the root curve to the list
8584  list_building_polygon_pt.push_back(root_curve_pt);
8585 
8586  // Get the initial and final vertices from the root curve
8587  Vector<double> root_curve_initial_vertex(2);
8588  Vector<double> root_curve_final_vertex(2);
8589 
8590  // We need to get the number of polylines that compose the root curve
8591  const unsigned nroot_curve_polyline = root_curve_pt.size();
8592  // ... and now get the initial and final vertex
8593  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8594  root_curve_pt[nroot_curve_polyline-1]->
8595  final_vertex_coordinate(root_curve_final_vertex);
8596 
8597  // First check if it already create a polygon
8598  double diff =
8599  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8600  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8601  +
8602  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8603  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8604  diff = sqrt(diff);
8605  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8606  {
8607  // The polyline already create a Polygon, then create it!!!
8608  // Create the curve section representation of the current root curve
8609  Vector<TriangleMeshCurveSection*>
8610  curve_section_pt(nroot_curve_polyline);
8611 
8612  // Copy the polylines into its curve section representation
8613  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8614  {curve_section_pt[i] = root_curve_pt[i];}
8615 
8616  // ... and create the Polygon
8617  TriangleMeshPolygon *new_polygon_pt =
8618  new TriangleMeshPolygon(curve_section_pt);
8619 
8620  // Mark the polygon for deletion (in the destructor)
8621  this->Free_polygon_pt.insert(new_polygon_pt);
8622 
8623  // Add the polygon to the output polygons
8624  polygons_pt.push_back(new_polygon_pt);
8625  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8626  // when the curve creates a Polygon by itself
8627  else
8628  {
8629  // Flag to continue iterating while curves be added to the left
8630  // or right of the list of curves
8631  bool added_curve = false;
8632 #ifdef PARANOID
8633  // Flag to know if the "loop" finish because a polygon was
8634  // created or because no more curves can be added to the left or
8635  // right
8636  bool polygon_created = false;
8637 #endif
8638  do
8639  {
8640  added_curve = false;
8641  // If the root curve does not create a closed polygon then add curves
8642  // to the left or right until the curves create a closed polygon
8643  for (unsigned ic = root_curve_idx+1; ic < ncurves; ic++)
8644  {
8645  if (!done_curve[ic])
8646  {
8647  // Get the current curve
8648  Vector<TriangleMeshPolyLine*> current_curve_pt =
8649  polylines_pt[ic];
8650 
8651  // We need to get the number of polylines that compose the
8652  // current curve
8653  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8654 
8655  // ... and get the initial and final coordinates for the current
8656  // curve
8657  Vector<double> current_curve_initial_vertex(2);
8658  Vector<double> current_curve_final_vertex(2);
8659 
8660  current_curve_pt[0]->
8661  initial_vertex_coordinate(current_curve_initial_vertex);
8662  current_curve_pt[ncurrent_curve_polyline-1]->
8663  final_vertex_coordinate(current_curve_final_vertex);
8664 
8665  // ---------------------------------------------------------------
8666  // Start adding curves to the left or right
8667  // ---------------------------------------------------------------
8668  diff =
8669  ((current_curve_final_vertex[0] - root_curve_initial_vertex[0])*
8670  (current_curve_final_vertex[0] - root_curve_initial_vertex[0]))
8671  +
8672  ((current_curve_final_vertex[1] - root_curve_initial_vertex[1])*
8673  (current_curve_final_vertex[1] - root_curve_initial_vertex[1]));
8674  diff = sqrt(diff);
8675  // CURRENT curve to the LEFT of the ROOT curve
8676  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8677  {
8678  // Add the current curve to the left
8679  list_building_polygon_pt.push_front(current_curve_pt);
8680  // Mark the curve as done
8681  done_curve[ic] = true;
8682  // Update the initial vertex values
8683  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8684  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8685  // Increase the number of sorted curves
8686  nsorted_curves++;
8687  // Set the flag to indicate that a curve was added to the list
8688  added_curve = true;
8689  break;
8690  }
8691 
8692  diff =
8693  ((current_curve_initial_vertex[0] - root_curve_initial_vertex[0])*
8694  (current_curve_initial_vertex[0] - root_curve_initial_vertex[0]))
8695  +
8696  ((current_curve_initial_vertex[1] - root_curve_initial_vertex[1])*
8697  (current_curve_initial_vertex[1] - root_curve_initial_vertex[1]));
8698  diff = sqrt(diff);
8699  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8700  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8701  {
8702  Vector<TriangleMeshPolyLine*>
8703  tmp_curve_pt(ncurrent_curve_polyline);
8704  // Reverse each polyline and back them up
8705  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8706  {
8707  current_curve_pt[it]->reverse();
8708  tmp_curve_pt[it] = current_curve_pt[it];
8709  }
8710  // Now copy them back but in reverse order
8711  unsigned count = 0;
8712  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8713  {current_curve_pt[count] = tmp_curve_pt[i];}
8714  // Add the current curve to the left
8715  list_building_polygon_pt.push_front(current_curve_pt);
8716  // Mark the curve as done
8717  done_curve[ic] = true;
8718  // Update the initial vertex values
8719  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8720  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8721  // Increase the number of sorted curves
8722  nsorted_curves++;
8723  // Set the flag to indicate that a curve was added to the list
8724  added_curve = true;
8725  break;
8726  }
8727 
8728  diff =
8729  ((current_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8730  (current_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8731  +
8732  ((current_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8733  (current_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8734  diff = sqrt(diff);
8735  // CURRENT curve to the RIGHT of the ROOT curve
8736  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8737  {
8738  // Add the current curve to the right
8739  list_building_polygon_pt.push_back(current_curve_pt);
8740  // Mark the curve as done
8741  done_curve[ic] = true;
8742  // Update the initial vertex values
8743  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8744  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8745  // Increase the number of sorted curves
8746  nsorted_curves++;
8747  // Set the flag to indicate that a curve was added to the list
8748  added_curve = true;
8749  break;
8750  }
8751 
8752  diff =
8753  ((current_curve_final_vertex[0] - root_curve_final_vertex[0])*
8754  (current_curve_final_vertex[0] - root_curve_final_vertex[0]))
8755  +
8756  ((current_curve_final_vertex[1] - root_curve_final_vertex[1])*
8757  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8758  diff = sqrt(diff);
8759  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8760  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8761  {
8762  Vector<TriangleMeshPolyLine*>
8763  tmp_curve_pt(ncurrent_curve_polyline);
8764  // Reverse each polyline and back them up
8765  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8766  {
8767  current_curve_pt[it]->reverse();
8768  tmp_curve_pt[it] = current_curve_pt[it];
8769  }
8770  // Now copy them back but in reverse order
8771  unsigned count = 0;
8772  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8773  {current_curve_pt[count] = tmp_curve_pt[i];}
8774  // Add the current curve to the right
8775  list_building_polygon_pt.push_back(current_curve_pt);
8776  // Mark the curve as done
8777  done_curve[ic] = true;
8778  // Update the initial vertex values
8779  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8780  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8781  // Increase the number of sorted curves
8782  nsorted_curves++;
8783  // Set the flag to indicate that a curve was added to the list
8784  added_curve = true;
8785  break;
8786  }
8787 
8788  } // if (!done_curve[ic])
8789 
8790  } // for (ic < ncurves)
8791 
8792  // After adding a curve check if it is possible to create a polygon
8793  double diff =
8794  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8795  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8796  +
8797  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8798  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8799  diff = sqrt(diff);
8800  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8801  {
8802  // If the curves already create a Polygon then go out of the
8803  // loop and create the Polygon
8804  added_curve = false;
8805 #ifdef PARANOID
8806  // Set the flag to indicate that a Polygon has been created
8807  polygon_created = true;
8808 #endif
8809  } // (diff <
8810  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8811  // when the curve creates a Polygon by itself
8812 
8813  }while(added_curve);
8814 
8815 #ifdef PARANOID
8816  if (!polygon_created)
8817  {
8818  std::stringstream error_message;
8819  error_message
8820  << "It was no possible to create a TriangleMeshPolygon with "
8821  << "the input set of curves\n"
8822  << "These are the initial and final vertices in the current "
8823  << "sorted list of\nTriangleMeshPolyLines\n\n";
8824  Vector<double> init_vertex(2);
8825  Vector<double> final_vertex(2);
8826  unsigned icurve = 0;
8827  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8828  = list_building_polygon_pt.begin();
8829  it != list_building_polygon_pt.end(); it++, icurve++)
8830  {
8831  const unsigned ncurrent_curve_polyline = (*it).size();
8832  error_message
8833  << "TriangleMeshCurve #" << icurve << "\n"
8834  << "-----------------------------------\n";
8835  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8836  {
8837  Vector<double> init_vertex(2);
8838  Vector<double> final_vertex(2);
8839  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8840  (*it)[ip]->final_vertex_coordinate(final_vertex);
8841  error_message
8842  <<"TriangleMeshPolyLine #" << ip << "\n"
8843  <<"Initial vertex: ("<<init_vertex[0]<<","<<init_vertex[1]<<")\n"
8844  <<"Final vertex: ("<<final_vertex[0]<<","<<final_vertex[1]<<")\n";
8845  } // for (ip < ncurrent_curve_polyline)
8846  } // for (it != list_building_polygon_pt.end())
8847 
8848  throw OomphLibError(error_message.str(),
8849  "TriangleMesh::create_tmp_polygons_helper()",
8850  OOMPH_EXCEPTION_LOCATION);
8851 
8852  } // if (!polygon_created)
8853 #endif
8854 
8855  // Create the polygon after joining the curves
8856  unsigned ntotal_polylines = 0;
8857  // Get the total number of polylines
8858  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8859  = list_building_polygon_pt.begin();
8860  it != list_building_polygon_pt.end(); it++)
8861  {
8862  ntotal_polylines+=(*it).size();
8863  }
8864 
8865  // Create the curve section representation of the curves on the list
8866  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8867 
8868  // Copy the polylines into its curve section representation
8869  unsigned counter = 0;
8870  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8871  = list_building_polygon_pt.begin();
8872  it != list_building_polygon_pt.end(); it++)
8873  {
8874  const unsigned ncurrent_curve_polyline = (*it).size();
8875  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++,counter++)
8876  {
8877  curve_section_pt[counter] = (*it)[ip];
8878  } // for (ip < ncurrent_curve_polyline)
8879  } // Loop over the list of polylines
8880 
8881  // ... and create the Polygon
8882  TriangleMeshPolygon *new_polygon_pt =
8883  new TriangleMeshPolygon(curve_section_pt);
8884 
8885  // Mark the polygon for deletion (in the destructor)
8886  this->Free_polygon_pt.insert(new_polygon_pt);
8887 
8888  // Add the polygon to the output polygons
8889  polygons_pt.push_back(new_polygon_pt);
8890 
8891  } // else
8892  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8893 
8894  }while(nsorted_curves < nunsorted_curves);
8895 
8896  }
8897 
8898  //======================================================================
8899  //\short Take the polylines from the original open curves and created
8900  //new temporaly representations of open curves with the bits of
8901  //original curves not overlapped by shared boundaries
8902  //======================================================================
8903  template<class ELEMENT>
8905  Vector<Vector<TriangleMeshPolyLine *> > &sorted_open_curves_pt,
8906  Vector<TriangleMeshPolyLine*> &unsorted_shared_to_internal_poly_pt,
8907  Vector<TriangleMeshOpenCurve *> &open_curves_pt)
8908  {
8909  // Here search for the connections of the open curves remaining as
8910  // open curves with the shared boundaries markes as internal
8911  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
8912 
8913  // Once identified the connections created with the new internal
8914  // boundaries representations add them to the open curves container
8915  for (unsigned i = 0; i < ninternal_open_curves; i++)
8916  {
8917  // Create the curve section representation of the polylines
8918  const unsigned npoly = sorted_open_curves_pt[i].size();
8919  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
8920  for (unsigned j = 0; j < npoly; j++)
8921  {
8922  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
8923  }
8924  // ... and create the Open Curve
8925  TriangleMeshOpenCurve *new_open_curve_pt =
8926  new TriangleMeshOpenCurve(tmp_curve_section);
8927 
8928  // Mark the open curve for deletion (in the destructor)
8929  this->Free_open_curve_pt.insert(new_open_curve_pt);
8930 
8931  // Add the open curve to the output open curves
8932  open_curves_pt.push_back(new_open_curve_pt);
8933 
8934  } // (i < ninternal_open_curves)
8935 
8936  }
8937 
8938  //======================================================================
8939  //\short Check for any possible connections that the array of sorted
8940  //nodes have with original boundary nodes, previous shared polyline
8941  //nodes or with itself polyline nodes. In case that there is a
8942  //connection, get the boundary id to which connects
8943  //======================================================================
8944  template<class ELEMENT>
8946  std::set<FiniteElement*> &element_in_processor_pt,
8947  const int &root_edge_bnd_id,
8948  std::map<std::pair<Node*,Node*>, bool> &overlapped_face,
8949  std::map<unsigned, std::map<Node*, bool> >
8950  &node_on_bnd_not_overlapped_by_shd_bnd,
8951  std::list<Node*> &current_polyline_nodes,
8952  std::map<unsigned, std::list<Node*> >
8953  &shared_bnd_id_to_sorted_list_node_pt,
8954  const unsigned &node_degree,
8955  Node* &new_node_pt,
8956  const bool called_from_load_balance)
8957  {
8958  // Initialize the flag to return
8959  int flag_to_return = -1;
8960 
8961  // --------------------------------------------------------------------
8962  // First try to find a connection with any original boundary (keep
8963  // in mind the case when internal boundaries may be overlapped by
8964  // shared boundaries)
8965  // --------------------------------------------------------------------
8966 
8967  // Check if the shared boundary is overlapping an internal boundary
8968  bool overlapping_internal_boundary = false;
8969  // The boundary id overlapped by the current shared boundary
8970  unsigned internal_overlaping_bnd_id = 0;
8971  if (root_edge_bnd_id != -1)
8972  {
8973  // Set the flat to true
8974  overlapping_internal_boundary = true;
8975  // Set the bnd id of the overlapped internal boundary
8976  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
8977  } // if (root_edge_bnd_id != -1)
8978 
8979  // ---------------------------------------------------------------
8980  // Check if the connection is with an original boundary by checking
8981  // if the new node is a boundary node, and it lives in an element
8982  // that is part of the domain
8983  // ---------------------------------------------------------------
8984  if (new_node_pt->is_on_boundary())
8985  {
8986  // Flag to indicate if the node lives in a non overlapped boundary
8987  bool is_node_living_in_non_overlapped_boundary = false;
8988 
8989  // If the node is a boundary node then check in which boundary it
8990  // is
8991  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
8992  for (unsigned bb=0;bb<noriginal_bnd;bb++)
8993  {
8994  // If the shared boundary overlaps an internal boundary it will
8995  // be indicated by (root_edge_bnd_id != -1), the original
8996  // internal boundary that overlaps is given by the
8997  // root_edge_bnd_id value. We skip that original internal
8998  // boundary because the new node will be obviously ON the
8999  // internal boundary
9000  if (overlapping_internal_boundary)
9001  {
9002  // Is the node on boundary bb?
9003  if (new_node_pt->is_on_boundary(bb))
9004  {
9005  // If overlaping then check that the boundary is different
9006  // from the one that is being overlapped, or if overlapped
9007  // then check that the node is on an edge on the bb
9008  // boundary not overlapped by a shared boundary
9009  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9010  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9011  if (bb != internal_overlaping_bnd_id ||
9012  ((bb == internal_overlaping_bnd_id) &&
9013  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9014  {
9015  // Is the node living in a non overlapped boundary
9016  if (bb != internal_overlaping_bnd_id)
9017  {
9018  is_node_living_in_non_overlapped_boundary = true;
9019  }
9020 
9021  // Now we need to check that the node lies on a boundary
9022  // that still exist (the elements associated to the
9023  // boundary may have been removed at the mesh distribution
9024  // stage). The node may be still marked as a boundary node
9025  // but the boundary may not have elements associated.
9026 
9027  // Get the number of elements in the boundary
9028  const unsigned n_bound_ele = this->nboundary_element(bb);
9029  if (n_bound_ele > 0)
9030  {
9031  // Check that node lies on a nonhalo element, those are
9032  // the elements used to update the domain representation
9033  for (unsigned e = 0; e < n_bound_ele; e++)
9034  {
9035  // Get the boundary bulk element
9036  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9037  // Check if the element will be retained, it means it
9038  // is a nonhalo element
9039  std::set<FiniteElement*>::iterator it =
9040  element_in_processor_pt.find(bulk_ele_pt);
9041  // If found then check if the node live in the element
9042  if (it!=element_in_processor_pt.end())
9043  {
9044  // Found the node in the nonhalo face element
9045  bool found_node = false;
9046  // Get the face index
9047  int face_index = this->face_index_at_boundary(bb, e);
9048  // Create the face element
9049  FiniteElement* face_ele_pt =
9050  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9051  // Get the number of nodes in the face element
9052  const unsigned n_node_face = face_ele_pt->nnode();
9053  // Get the first and last node of the face element
9054  Node* first_node_pt = face_ele_pt->node_pt(0);
9055  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9056  // Create the edge with the pair of nodes
9057  std::pair<Node*, Node*> tmp_edge =
9058  std::make_pair(first_node_pt, last_node_pt);
9059  // Check if the face element edge is overlapped by a
9060  // shared boundary
9061  // Is the face not overlapped?
9062  if (!overlapped_face[tmp_edge])
9063  {
9064  // Look for the node in the current face element
9065  for (unsigned n = 0; n < n_node_face; n++)
9066  {
9067  // Check for every individual node
9068  if (face_ele_pt->node_pt(n) == new_node_pt)
9069  {
9070  found_node = true;
9071  break;
9072  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9073  } // for (n < n_node_face)
9074  } // if (!overlapped_face[tmp_edge])
9075  // Free the memory of the face element
9076  delete face_ele_pt;
9077  if (found_node)
9078  {
9079  // return the first original boundary id found,
9080  // does not matter if the node lies on more than
9081  // one original boundary (with boundary
9082  // elements). This is the original boundary id
9083  // that will be used to create the connection
9084  flag_to_return = bb;
9085  return flag_to_return;
9086  } // if (found_node)
9087 
9088  } // if (it!=element_in_processor_pt.end())
9089 
9090  } // for (e < n_bound_ele)
9091 
9092  } // if (n_bound_ele > 0)
9093 
9094  } // if (bb != internal_overlaping_bnd_id ||
9095  // ((bb == internal_overlaping_bnd_id) &&
9096  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9097 
9098  } // if (nod_pt->is_on_boundary(bb))
9099 
9100  } // if (overlapping_internal_boundary)
9101  else
9102  {
9103  // Is the node on boundary bb?
9104  if (new_node_pt->is_on_boundary(bb))
9105  {
9106  // Now we need to check that the node lies on a boundary
9107  // that still exist (the elements associated to the boundary
9108  // may have been removed at the mesh distribution
9109  // stage). The node may be still marked as a boundary node
9110  // but the boundary may not have elements associated.
9111 
9112  // Get the number of elements in the boundary
9113  const unsigned n_bound_ele = this->nboundary_element(bb);
9114  if (n_bound_ele > 0)
9115  {
9116  // Check that node lies on a nonhalo element, those are
9117  // the elements used to update the domain representation
9118  for (unsigned e = 0; e < n_bound_ele; e++)
9119  {
9120  // Get the boundary bulk element
9121  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9122  // Check if the element will be retained, it means it is
9123  // a nonhalo element
9124  std::set<FiniteElement*>::iterator it =
9125  element_in_processor_pt.find(bulk_ele_pt);
9126  // If found then check if the node live in the element
9127  if (it!=element_in_processor_pt.end())
9128  {
9129  // Found the node in the nonhalo face element
9130  bool found_node = false;
9131  // Get the face index
9132  int face_index = this->face_index_at_boundary(bb, e);
9133  // Create the face element
9134  FiniteElement* face_ele_pt =
9135  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9136  // Get the number of nodes in the face element
9137  const unsigned n_node_face = face_ele_pt->nnode();
9138  // Get the first and last node of the face element
9139  Node* first_node_pt = face_ele_pt->node_pt(0);
9140  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9141  // Create the edge with the pair of nodes
9142  std::pair<Node*, Node*> tmp_edge =
9143  std::make_pair(first_node_pt, last_node_pt);
9144  // Check if the face element edge is overlapped by a
9145  // shared boundary
9146  // Is the face not overlapped?
9147  if (!overlapped_face[tmp_edge])
9148  {
9149  // Look for the node in the current face element
9150  for (unsigned n = 0; n < n_node_face; n++)
9151  {
9152  // Check for every individual node
9153  if (face_ele_pt->node_pt(n) == new_node_pt)
9154  {
9155  found_node = true;
9156  break;
9157  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9158  } // for (n < n_node_face)
9159  } // if (!overlapped_face[tmp_edge])
9160  // Free the memory of the face element
9161  delete face_ele_pt;
9162  if (found_node)
9163  {
9164  // return the first original boundary id found, does
9165  // not matter if the node lies on more than one
9166  // original boundary (with boundary elements). This
9167  // is the original boundary id that will be used to
9168  // create the connection
9169  flag_to_return = bb;
9170  return flag_to_return;
9171  } // if (found_node)
9172 
9173  } // if (it!=element_in_processor_pt.end())
9174 
9175  } // for (e < n_bound_ele)
9176 
9177  } // if (n_bound_ele > 0)
9178 
9179  } // if (nod_pt->is_on_boundary(bb))
9180  } // else if (overlapping_internal_boundary)
9181  } // for (bb < noriginal_bnd)
9182 
9183  // We will only reach this stage when the node was found to be
9184  // connected to an original boundary but the element(s) on that
9185  // boundary where the node should live are not part of the domain.
9186  // Think in a corner of a triangle which touches the boundary
9187  // which elements will not be part of the domain
9188 
9189  // We need to break the currently forming polyline
9190  //flag_to_return = -3;
9191 
9192  // We need to break the currently forming polyline if and only if
9193  // the boundary(ies) in which the node is living is(are) not an
9194  // overlapped boundary
9195  if (!overlapping_internal_boundary)
9196  {
9197  // If the boundary(ies) in which the node is living is(are) an
9198  // overlapped boundary then break the break the formation of the
9199  // polyline
9200  flag_to_return = -3;
9201  }
9202  else
9203  {
9204  // The boundary is overlapped, if the node lives in a non
9205  // overlapped boundary then we can break the formation of the
9206  // polyline
9207  if (is_node_living_in_non_overlapped_boundary)
9208  {
9209  flag_to_return = -3;
9210  } // if (is_node_living_in_non_overlapped_boundar)y
9211 
9212  } // if (!overlapping_internal_boundary)
9213 
9214  } // if (new_node_pt->is_on_boundary())
9215 
9216  // Return inmediately if the connection is with an original boundary
9217  // whose elements are still part of the domain
9218  if (flag_to_return >= 0)
9219  {
9220  return flag_to_return;
9221  }
9222 
9223  // ----------------------------------------------------------------------
9224  // Secondly, if there is not a connection with any original
9225  // boundary, or if there is connection but with an original boundary
9226  // whose elements are not part of the domain, then check for
9227  // connections with previously created shared polylines
9228  // ----------------------------------------------------------------------
9229  // Store all the previous shared polylines to which the current
9230  // found is found to be connected
9231  Vector<unsigned> candidate_shared_bnd_to_connect;
9232  // Check for all the previous polylines except the current one
9233  for (std::map<unsigned, std::list<Node*> >::iterator it =
9234  shared_bnd_id_to_sorted_list_node_pt.begin();
9235  it != shared_bnd_id_to_sorted_list_node_pt.end();
9236  it++)
9237  {
9238  // Get the boundary id of the list of nodes that created the
9239  // polyline (the shared boundary id associated with the list of
9240  // nodes)
9241  const unsigned i_bnd_id = (*it).first;
9242  // Get an iterator pointer to the list of nodes of the shared
9243  // polyline
9244  std::list<Node*>::iterator it_list = (*it).second.begin();
9245  // Get the total number of nodes associated to the boundary
9246  const unsigned n_nodes = (*it).second.size();
9247  // Search for connections in the list of nodes
9248  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9249  {
9250  // Is the node already part of any other shared boundary
9251  if ((*it_list) == new_node_pt)
9252  {
9253  // Include the i-th boundary id in the list of candidate
9254  // shared boundaries to connect
9255  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9256  // Break the look with the i-th shared boundary, check with
9257  // the others shared boundaries
9258  break;
9259  } // if ((*it_list) == new_node_pt)
9260 
9261  } // for (i < nnodes)
9262 
9263  } // Loop over the shared boundaries and associated nodes
9264 
9265  // Get the number of candidate shared boundaries to connect
9266  const unsigned n_candidate_shared_bnd_to_connect =
9267  candidate_shared_bnd_to_connect.size();
9268 
9269  // Is there a connection with any previous shared polyline
9270  if (n_candidate_shared_bnd_to_connect > 0)
9271  {
9272  // If called from load balance we do not need to check if the
9273  // shared boundary is part of the processor since it certanily is,
9274  // only the shared boundaries that are pare of the processor are
9275  // used to created connection when creating the new shared
9276  // boundaries in the load balance rutine
9277  if (called_from_load_balance)
9278  {
9279  return candidate_shared_bnd_to_connect[0];
9280  }
9281 
9282  // We need to ensure that the shared boundary to which we are
9283  // connecting is part of the current processor, if none of the
9284  // found shared bundaries is in the current processor then return
9285  // the flag for "connection with boundary not in the current
9286  // processor"
9287 
9288  // Store the shared boundaries associated with the current processor
9289  Vector<unsigned> shared_bound_in_this_proc;
9290 
9291  // Get the shared boundaries associated with the current processor
9292  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9293 
9294  // If any of the candidate shared boundaries to connect is in the
9295  // current processor then return that shared boundary id
9296 
9297  // The number of shared boundaries in the current processor
9298  const unsigned n_shared_bound_in_this_proc =
9299  shared_bound_in_this_proc.size();
9300 
9301  // Loop over the candidate shared boundaries to connect
9302  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9303  {
9304  // Get the i-th candidate shared boundary to connect
9305  const unsigned i_candidate_shared_bnd =
9306  candidate_shared_bnd_to_connect[i];
9307 
9308  // Loop over the shared boundaries in the current processor
9309  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9310  {
9311  // Is the candidate boundary a shared boundary in this processor?
9312  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9313  {
9314  // Return the candidate shared boundary
9315  flag_to_return = i_candidate_shared_bnd;
9316  return flag_to_return;
9317  } // The candidate shared boundary is a boundary in the
9318  // current processor
9319 
9320  } // for (j < n_shared_bound_in_this_proc)
9321 
9322  } // for (i < n_candidate_shared_bnd_to_connect)
9323 
9324  // If non of the candidate shared boundaries to connect is in the
9325  // current processor the mark that we need to stop the addition of
9326  // vertices at this side of the polyline
9327  flag_to_return = -3;
9328 
9329  } // if (n_candidate_shared_bnd_to_connect > 0)
9330 
9331  // Return inmediately if the connection is with a previuos shared
9332  // boundary
9333  if (flag_to_return >= 0)
9334  {
9335  return flag_to_return;
9336  }
9337 
9338  // ------------------------------------------------------------------
9339  // Finally,check for connections with the same polyline (the shared
9340  // boundary that is being constructed). We are trying to avoid loops
9341  // or connections with the same shared boundary that is why this is
9342  // checked at the end
9343  // ------------------------------------------------------------------
9344  unsigned nrepeated = 0;
9345  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9346  it_list != current_polyline_nodes.end();
9347  it_list++)
9348  {
9349  // There must be at least one repeated node (the one that we have
9350  // just added, and it should be the first or last node)
9351  if ((*it_list) == new_node_pt) {nrepeated++;}
9352  }
9353  // If the number of repeated nodes is greater than one then the
9354  // polyline has a connection with itself
9355  if (nrepeated > 1)
9356  {
9357  // Return the flag value to indicate connection with itself, we
9358  // can not return the boundary id of the current polyline since it
9359  // has not been already assigned
9360  flag_to_return = -2;
9361  }
9362 
9363  // If there is no connection at all check the degree of the node, if
9364  // it is greater than 2 then return the flag to stop adding nodes
9365  // after this one
9366  if (node_degree > 2)
9367  {
9368  flag_to_return = -3;
9369  }
9370 
9371  // Return the flag
9372  return flag_to_return;
9373 
9374  }
9375 
9376  //======================================================================
9377  // \short Establish the connections of the polylines previously
9378  // marked as having connections. This connections were created in the
9379  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9380  // In case of doing load balancing the connections were created by the
9381  // function RefineableTriangleMesh::create_new_shared_boundaries()
9382  // ======================================================================
9383  template<class ELEMENT>
9385  {
9386  // Get the rank of the current processor
9387  const unsigned my_rank = this->communicator_pt()->my_rank();
9388 
9389  // Get the shared curves associated with this processor
9390  Vector<Vector<TriangleMeshPolyLine*> > shared_curves_pt =
9391  this->Shared_boundary_polyline_pt[my_rank];
9392 
9393  // Loop through the shared boundaries on the current processor and
9394  // check if they are marked to create a connection
9395  const unsigned ncurves = shared_curves_pt.size();
9396  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9397  {
9398  // Get the number of polylines in the current shared curve
9399  const unsigned npoly = shared_curves_pt[icurve].size();
9400  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9401  {
9402  // Get the polyline representation of the shared boundary
9403  TriangleMeshPolyLine *shd_poly_pt = shared_curves_pt[icurve][ipoly];
9404 
9405  // Get the boundary id of the current polyline
9406  const unsigned bound_id = shd_poly_pt->boundary_id();
9407 
9408  // Is the left vertex connected
9409  const bool is_connected_to_the_left =
9410  shd_poly_pt->is_initial_vertex_connected();
9411 
9412  // Is the right vertex connected
9413  const bool is_connected_to_the_right =
9414  shd_poly_pt->is_final_vertex_connected();
9415 
9416  // -----------------------------------------------------------------
9417  // If there is a connection at one of the ends we need to
9418  // establish that connection
9419  if (is_connected_to_the_left || is_connected_to_the_right)
9420  {
9421  // Now get the new left and right vertices of the shared
9422  // polyline
9423  const unsigned n_vertex = shd_poly_pt->nvertex();
9424 
9425  // Now get the polylines to where the current shared boundary is
9426  // connected and create the connections
9427 
9428  // --------------------------------------------------------------
9429  // Connection to the left
9430  if (is_connected_to_the_left)
9431  {
9432  // Get the unsigned version of the bound id to connect to
9433  // the left
9434  const unsigned uconnection_to_the_left =
9435  shd_poly_pt->initial_vertex_connected_bnd_id();
9436 
9437  // The pointer to the boundary to connect
9438  TriangleMeshPolyLine *poly_to_connect_pt = 0;
9439 
9440  // Flag to indicate we are trying to connect to an split
9441  // boundary
9442  bool connecting_to_an_split_boundary = false;
9443 
9444  // Flag to indicate we are trying to connecto to an internal
9445  // boundary that is overlaped by a shared boundary
9446  bool connecting_to_an_overlaped_boundary = false;
9447 
9448  // Check if the connection is with itself
9449  if (uconnection_to_the_left == bound_id)
9450  {
9451  // Set the pointer to the polyline to connect
9452  poly_to_connect_pt = shd_poly_pt;
9453  }
9454  else
9455  {
9456  // Get the initial shared boundary ids
9457  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9458  // Check if the boundary to connect is a shared polyline
9459  if (uconnection_to_the_left >= initial_shd_bnd_id)
9460  {
9461  // Get the polyline pointer representing the destination
9462  // boundary
9463  poly_to_connect_pt =
9464  boundary_polyline_pt(uconnection_to_the_left);
9465  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9466  else
9467  {
9468  // If we are going to connect to an original boundary
9469  // verify if the boundary was splitted during the
9470  // distribution process to consider all the chunks
9471  // (sub-polylines) of the boundary
9472  if (boundary_was_splitted(uconnection_to_the_left))
9473  {
9474  connecting_to_an_split_boundary = true;
9475  } // if (boundary_was_splitted(uconnection_to_the_left))
9476 
9477  // If we are going to connect to an original boundary
9478  // verify if the boundary, or any of its chunks is
9479  // marked to be overlapped by a shared boundary, if that
9480  // is the case we first check for connections in the
9481  // shared boundary that overlaps the internal boundary,
9482  // or the chunks, and then check for connections in the
9483  // original boundary
9484  if (connecting_to_an_split_boundary)
9485  {
9486  // Get the number of chucks that represent the
9487  // destination boundary
9488  const unsigned n_sub_poly =
9489  nboundary_subpolylines(uconnection_to_the_left);
9490  // Now loop over the chunks of the destination
9491  // boundary and if any of them is marked to be
9492  // overlaped by a shared boundary then set the flag
9493  // and break the loop
9494  for (unsigned ii =0; ii < n_sub_poly; ii++)
9495  {
9496  if (boundary_marked_as_shared_boundary(
9497  uconnection_to_the_left, ii))
9498  {
9499  // Mark the boundary as being overlaped by a
9500  // shared boundary
9501  connecting_to_an_overlaped_boundary = true;
9502  // Break, no need to look for more overlapings
9503  break;
9504  } // if (boundary_marked_as_shared_boundary(...))
9505  } // for (ii < n_sub_poly)
9506  } // if (connecting_to_an_split_boundary)
9507  else
9508  {
9509  // If not connecting to an split boundary then check
9510  // if the whole destination boundary is overlaped by
9511  // an internal boundary
9512  if (boundary_marked_as_shared_boundary(
9513  uconnection_to_the_left, 0))
9514  {
9515  // Mark the boundary as being overlaped by a shared
9516  // boundary
9517  connecting_to_an_overlaped_boundary = true;
9518  } // if (boundary_marked_as_shared_boundary(...))
9519  } // else if (connecting_to_an_split_boundary)
9520 
9521  // If we are connecting neither to an split boundary nor
9522  // an overlaped boundary then get the pointer to the
9523  // original boundary
9524  if (!(connecting_to_an_split_boundary ||
9525  connecting_to_an_overlaped_boundary))
9526  {
9527  // Get the polyline pointer representing the
9528  // destination boundary
9529  poly_to_connect_pt =
9530  boundary_polyline_pt(uconnection_to_the_left);
9531  } // else if (NOT split, NOT overlaped)
9532  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9533 
9534  } // else if (uconnection_to_the_left == bound_id)
9535 
9536 #ifdef PARANOID
9537  // If we are not connecting to an original boundary
9538  // (connecting to the same shared boundary or to another
9539  // shared boundary) then the boundary should not be marked
9540  // as split
9541  if (!connecting_to_an_split_boundary)
9542  {
9543  if (boundary_was_splitted(uconnection_to_the_left))
9544  {
9545  std::stringstream error;
9546  error
9547  << "The current shared boundary (" << bound_id << ") was "
9548  << "marked to have a connection\nto the left with the "
9549  << "boundary (" << uconnection_to_the_left << ").\n"
9550  << "The problem is that the destination boundary (possibly\n"
9551  << "another shared boundary) is marked to be split\n"
9552  << "There should not be split shared boundaries\n\n";
9553  throw OomphLibError(
9554  error.str(),
9555  "TriangleMesh::create_shared_polylines_connections()",
9556  OOMPH_EXCEPTION_LOCATION);
9557  }
9558  } // if (!connecting_to_an_split_boundary)
9559 #endif
9560 
9561  // Now look for the vertex number on the destination
9562  // boundary(ies) -- in case that the boundary was split ---
9563 
9564  // Do not check for same orientation, that was previously
9565  // worked by interchanging the connections boundaries (if
9566  // necessary)
9567 
9568  // Get the left vertex in the shared boundary
9569  Vector<double> shd_bnd_left_vertex =
9570  shd_poly_pt->vertex_coordinate(0);
9571 
9572  // If the boundary was not split then ...
9573  if (!connecting_to_an_split_boundary)
9574  {
9575  // ... check if the boundary is marked to be overlaped by
9576  // a shared boundary
9577  if (!connecting_to_an_overlaped_boundary)
9578  {
9579  // If that is not the case then we can safely look for
9580  // the vertex number on the destination boundar
9581  unsigned vertex_index = 0;
9582 
9583  const bool found_vertex_index =
9584  get_connected_vertex_number_on_destination_polyline(
9585  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9586 
9587  // If we could not find the vertex index to connect then
9588  // we are in trouble
9589  if (!found_vertex_index)
9590  {
9591  std::stringstream error;
9592  error
9593  << "The current shared boundary (" << bound_id << ") was "
9594  << "marked to have a connection\nto the left with the "
9595  << "boundary (" << uconnection_to_the_left << ").\n"
9596  << "The problem is that the left vertex of the current\n"
9597  << "shared boundary is not in the list of vertices of the\n"
9598  << "boundary to connect.\n\n"
9599  << "This is the left vertex of the current shared boundary\n"
9600  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9601  << shd_bnd_left_vertex[1] << ")\n\n"
9602  << "This is the list of vertices on the destination "
9603  << "boundary\n";
9604  const unsigned n_v = poly_to_connect_pt->nvertex();
9605  for (unsigned i = 0; i < n_v; i++)
9606  {
9607  Vector<double> cvertex =
9608  poly_to_connect_pt->vertex_coordinate(i);
9609  error
9610  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
9611  }
9612  throw OomphLibError(
9613  error.str(),
9614  "TriangleMesh::create_shared_polylines_connections()",
9615  OOMPH_EXCEPTION_LOCATION);
9616  } // if (!found_vertex_index)
9617 
9618  // Create the connection, the left vertex of the current
9619  // shared boundary is connected with the vertex_index-th
9620  // vertex on the destination boundary
9621  shd_poly_pt->connect_initial_vertex_to_polyline(
9622  poly_to_connect_pt, vertex_index);
9623 
9624  } // if (!connecting_to_an_overlaped_boundary)
9625  else
9626  {
9627  // If the boundary is marked to be overlaped by a shared
9628  // boundary then get that shared boundary and look for
9629  // the connection in that boundary
9630 
9631  // The vertex where to store the index to connect
9632  unsigned vertex_index = 0;
9633  // A flag to indicate if the connection was found
9634  bool found_vertex_index = false;
9635 
9636  // Get the shared boundary id that is overlaping the
9637  // internal boundary
9638  Vector<unsigned> dst_shd_bnd_ids;
9639  get_shared_boundaries_overlapping_internal_boundary(
9640  uconnection_to_the_left, dst_shd_bnd_ids);
9641 
9642  // Get the number of shared polylines that were found to
9643  // overlap the internal boundary
9644  const unsigned n_shd_bnd_overlap_int_bnd =
9645  dst_shd_bnd_ids.size();
9646 
9647  // Loop over the shared boundaries that overlap the
9648  // internal boundary and look for the vertex to connect
9649  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9650  {
9651  // Get the shared polyline
9652  const unsigned new_connection_to_the_left =
9653  dst_shd_bnd_ids[ss];
9654 
9655  // Get the shared polyline that is overlaping the
9656  // internal boundary
9657  poly_to_connect_pt =
9658  boundary_polyline_pt(new_connection_to_the_left);
9659 
9660  if (poly_to_connect_pt!=0)
9661  {
9662  // Look for the vertex number in the destination
9663  // shared polyline
9664  found_vertex_index =
9665  get_connected_vertex_number_on_destination_polyline(
9666  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9667  } // if (poly_to_connect_pt!=0)
9668 
9669  // If we have found the vertex to connect then
9670  // break the loop
9671  if (found_vertex_index)
9672  {
9673  break;
9674  } // if (found_vertex_index)
9675 
9676  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9677 
9678 #ifdef PARANOID
9679  // If we could not find the vertex index to connect then
9680  // we are in trouble
9681  if (!found_vertex_index)
9682  {
9683  std::stringstream error;
9684  error
9685  << "The current shared boundary (" << bound_id << ") was "
9686  << "marked to have a connection\nto the left with the "
9687  << "boundary (" << uconnection_to_the_left << ").\n"
9688  << "This last boundary is marked to be overlaped by "
9689  << "shared boundaries\n"
9690  << "The problem is that the left vertex of the current\n"
9691  << "shared boundary is not in the list of vertices of the\n"
9692  << "boundary to connect.\n\n"
9693  << "This is the left vertex of the current shared boundary\n"
9694  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9695  << shd_bnd_left_vertex[1] << ")\n\n"
9696  << "This is the list of vertices on the destination "
9697  << "boundary\n";
9698  Vector<unsigned> dst_shd_bnd_ids;
9699  get_shared_boundaries_overlapping_internal_boundary(
9700  uconnection_to_the_left, dst_shd_bnd_ids);
9701  const unsigned n_shd_bnd_overlap_int_bnd =
9702  dst_shd_bnd_ids.size();
9703  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9704  {
9705  const unsigned new_connection_to_the_left =
9706  dst_shd_bnd_ids[ss];
9707  poly_to_connect_pt =
9708  boundary_polyline_pt(new_connection_to_the_left);
9709  if (poly_to_connect_pt != 0)
9710  {
9711  const unsigned shd_bnd_id_overlap =
9712  poly_to_connect_pt->boundary_id();
9713  error << "Shared boundary id("
9714  << shd_bnd_id_overlap << ")\n";
9715  const unsigned n_v = poly_to_connect_pt->nvertex();
9716  for (unsigned i = 0; i < n_v; i++)
9717  {
9718  Vector<double> cvertex =
9719  poly_to_connect_pt->vertex_coordinate(i);
9720  error
9721  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9722  <<cvertex[1]<<")\n";
9723  }
9724  } // if (poly_to_connect_pt != 0)
9725  } // for (ss < n_shd_bnd_overlap_int_bnd)
9726 
9727  throw OomphLibError(
9728  error.str(),
9729  "TriangleMesh::create_shared_polylines_connections()",
9730  OOMPH_EXCEPTION_LOCATION);
9731 
9732  } // if (!found_vertex_index)
9733 #endif
9734 
9735  // Create the connection, the left vertex of the current
9736  // shared boundary is connected with the vertex_index-th
9737  // vertex on the destination boundary
9738  shd_poly_pt->connect_initial_vertex_to_polyline(
9739  poly_to_connect_pt, vertex_index);
9740 
9741  } // else if (!connecting_to_an_overlaped_boundary)
9742 
9743  } // if (!connecting_to_an_split_boundary)
9744  else
9745  {
9746  // If the boundary was split then we need to look for the
9747  // vertex in the sub-polylines
9748 
9749  // Get the sub-polylines vector
9750  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9751  boundary_subpolylines(uconnection_to_the_left);
9752 
9753  // Get the number of sub-polylines
9754  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9755 #ifdef PARANOID
9756  if (nsub_poly <= 1)
9757  {
9758  std::ostringstream error_message;
9759  error_message
9760  <<"The boundary (" << uconnection_to_the_left << ") was "
9761  << "marked to be splitted but\n"
9762  << "there are only ("<<nsub_poly<<") polylines to "
9763  << "represent it.\n";
9764  throw OomphLibError(
9765  error_message.str(),
9766  "TriangleMesh::create_shared_polylines_connections()",
9767  OOMPH_EXCEPTION_LOCATION);
9768  } // if (nsub_poly <= 1)
9769 #endif
9770  // We need to check if the boundary is marked to be
9771  // overlaped by an internal boundary, if that is the case
9772  // we need to check for each indivual subpolyline, and for
9773  // those overlaped by a shared polyline look for the
9774  // vertex in the shared polyline representation instead of
9775  // the original subpolyline
9776 
9777  // ... check if the boundary is marked to be overlaped by
9778  // a shared boundary
9779  if (!connecting_to_an_overlaped_boundary)
9780  {
9781  // We can work without checking the subpolylines
9782  // individually
9783 
9784  // The vertex where to store the index to connect
9785  unsigned vertex_index = 0;
9786  // The subpoly number to connect
9787  unsigned sub_poly_to_connect = 0;
9788  // A flag to indicate if the connection was found
9789  bool found_vertex_index = false;
9790 
9791  // Look for the vertex number to connect on each of the
9792  // subpolyines
9793  for (unsigned isub = 0; isub < nsub_poly; isub++)
9794  {
9795  // Assign the pointer to the sub-polyline
9796  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9797  // Search for the vertex in the current sub-polyline
9798  found_vertex_index =
9799  get_connected_vertex_number_on_destination_polyline(
9800  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9801  // If we have found the vertex to connect then break the
9802  // loop
9803  if (found_vertex_index)
9804  {
9805  // But first save the subpoly number (chunk), that
9806  // will be used to perform the connection
9807  sub_poly_to_connect = isub;
9808  break;
9809  } // if (found_vertex_index)
9810  } // for (isub < nsub_poly)
9811 
9812 #ifdef PARANOID
9813  // If we could not find the vertex index to connect then
9814  // we are in trouble
9815  if (!found_vertex_index)
9816  {
9817  std::stringstream error;
9818  error
9819  << "The current shared boundary (" << bound_id << ") was "
9820  << "marked to have a connection\nto the left with the "
9821  << "boundary (" << uconnection_to_the_left << ").\n"
9822  << "The problem is that the left vertex of the current\n"
9823  << "shared boundary is not in the list of vertices of any\n"
9824  << "of the sub polylines that represent the boundary to\n"
9825  << "connect.\n\n"
9826  << "This is the left vertex of the current shared boundary\n"
9827  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9828  << shd_bnd_left_vertex[1] << ")\n\n"
9829  << "This is the list of vertices on the destination "
9830  << "boundary\n";
9831  for (unsigned p = 0; p < nsub_poly; p++)
9832  {
9833  error << "Subpolyline #("<< p << ")\n";
9834  poly_to_connect_pt = tmp_vector_subpolylines[p];
9835  const unsigned n_v = poly_to_connect_pt->nvertex();
9836  for (unsigned i = 0; i < n_v; i++)
9837  {
9838  Vector<double> cvertex =
9839  poly_to_connect_pt->vertex_coordinate(i);
9840  error
9841  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9842  <<cvertex[1]<<")\n";
9843  }
9844  } // for (p < nsub_poly)
9845  throw OomphLibError(
9846  error.str(),
9847  "TriangleMesh::create_shared_polylines_connections()",
9848  OOMPH_EXCEPTION_LOCATION);
9849  } // if (!found_vertex_index)
9850 #endif
9851 
9852  // Create the connection, the left vertex of the current
9853  // shared boundary is connected with the vertex_index-th
9854  // vertex of sub_poly_to_connect-th subpolyline of the
9855  // destination boundary
9856  shd_poly_pt->connect_initial_vertex_to_polyline(
9857  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9858 
9859  } // if (!connecting_to_an_overlaped_boundary)
9860  else
9861  {
9862  // We first look on the shared boundaries that overlap
9863  // the internal boundaries and the look for the
9864  // sub-polylines that are not marked as being overlaped
9865  // by shared boundaries
9866 
9867  // The vertex where to store the index to connect
9868  unsigned vertex_index = 0;
9869  // The subpoly number to connect
9870  unsigned sub_poly_to_connect = 0;
9871  // A flag to indicate if the connection was found
9872  bool found_vertex_index = false;
9873 
9874  // Get the shared boundaries id that are overlaping the
9875  // internal boundary
9876  Vector<unsigned> dst_shd_bnd_ids;
9877  get_shared_boundaries_overlapping_internal_boundary(
9878  uconnection_to_the_left, dst_shd_bnd_ids);
9879 
9880  // Get the number of shared polylines that were found to
9881  // overlap the internal boundary
9882  const unsigned n_shd_bnd_overlap_int_bnd =
9883  dst_shd_bnd_ids.size();
9884 
9885  // Loop over the shared boundaries that overlap the
9886  // internal boundary and look for the vertex to connect
9887  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9888  {
9889  // Get the shared polyline
9890  const unsigned new_connection_to_the_left =
9891  dst_shd_bnd_ids[ss];
9892 
9893  // Make sure that the destination polyline is not the
9894  // same as the current shared polyline
9895  if (bound_id != new_connection_to_the_left)
9896  {
9897  // Get the shared polyline that is overlaping the
9898  // internal boundary
9899  poly_to_connect_pt =
9900  boundary_polyline_pt(new_connection_to_the_left);
9901 
9902  if (poly_to_connect_pt != 0)
9903  {
9904  // Look for the vertex number in the destination
9905  // shared polyline
9906  found_vertex_index =
9907  get_connected_vertex_number_on_destination_polyline(
9908  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9909  } // if (poly_to_connect_pt != 0)
9910 
9911  // If we have found the vertex to connect then
9912  // break the loop
9913  if (found_vertex_index)
9914  {
9915  break;
9916  } // if (found_vertex_index)
9917 
9918  } // if (bound_id != new_connection_to_the_left)
9919 
9920  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9921 
9922  // If we have not yet found the vertex then look for it
9923  // in the sub-polylines that are not overlaped by shared
9924  // boundaries
9925  if (!found_vertex_index)
9926  {
9927  // Look for the vertex number to connect on each of
9928  // the subpolyines
9929  for (unsigned isub = 0; isub < nsub_poly; isub++)
9930  {
9931  // Only work with those sub-polylines that are not
9932  // overlaped by shared boundaries
9933  if (!boundary_marked_as_shared_boundary(
9934  uconnection_to_the_left, isub))
9935  {
9936  // Assign the pointer to the sub-polyline
9937  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9938  // Search for the vertex in the current sub-polyline
9939  found_vertex_index =
9940  get_connected_vertex_number_on_destination_polyline(
9941  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9942  // If we have found the vertex to connect then break the
9943  // loop
9944  if (found_vertex_index)
9945  {
9946  // But first save the subpoly number (chunk), that
9947  // will be used to perform the connection
9948  sub_poly_to_connect = isub;
9949  break;
9950  } // if (found_vertex_index)
9951 
9952  } // if (not overlaped by shared boundary)
9953 
9954  } // for (isub < nsub_poly)
9955 
9956  } // if (!found_vertex_index)
9957 
9958 #ifdef PARANOID
9959  // If we could not find the vertex index to connect then
9960  // we are in trouble
9961  if (!found_vertex_index)
9962  {
9963  std::stringstream error;
9964  error
9965  << "The current shared boundary (" << bound_id << ") was "
9966  << "marked to have a connection\nto the left with the "
9967  << "boundary (" << uconnection_to_the_left << ").\n"
9968  << "This last boundary is marked to be overlaped by "
9969  << "shared boundaries\n"
9970  << "The problem is that the left vertex of the current\n"
9971  << "shared boundary is not in the list of vertices of "
9972  << "the\nboundary to connect.\n\n"
9973  << "This is the left vertex of the current shared "
9974  << "boundary\n"
9975  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9976  << shd_bnd_left_vertex[1] << ")\n\n"
9977  << "This is the list of vertices on the destination "
9978  << "boundary (only those subpolylines not marked as "
9979  << "overlaped by\nshared boundaries)\n";
9980  for (unsigned p = 0; p < nsub_poly; p++)
9981  {
9982  if (!boundary_marked_as_shared_boundary(
9983  uconnection_to_the_left, p))
9984  {
9985  error << "Subpolyline #("<< p << ")\n";
9986  poly_to_connect_pt = tmp_vector_subpolylines[p];
9987  const unsigned n_v = poly_to_connect_pt->nvertex();
9988  for (unsigned i = 0; i < n_v; i++)
9989  {
9990  Vector<double> cvertex =
9991  poly_to_connect_pt->vertex_coordinate(i);
9992  error
9993  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9994  <<cvertex[1]<<")\n";
9995  }
9996  } // Not marked as overlaped
9997  } // for (p < nsub_poly)
9998  error << "\nThis is the list of vertices of the shared "
9999  << "polylines that overlap\nthe internal "
10000  << "boundary\n";
10001  Vector<unsigned> dst_shd_bnd_ids;
10002  get_shared_boundaries_overlapping_internal_boundary(
10003  uconnection_to_the_left, dst_shd_bnd_ids);
10004  const unsigned n_shd_bnd_overlap_int_bnd =
10005  dst_shd_bnd_ids.size();
10006  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10007  {
10008  const unsigned new_connection_to_the_left =
10009  dst_shd_bnd_ids[ss];
10010  poly_to_connect_pt =
10011  boundary_polyline_pt(new_connection_to_the_left);
10012  if (poly_to_connect_pt != 0)
10013  {
10014  const unsigned shd_bnd_id_overlap =
10015  poly_to_connect_pt->boundary_id();
10016  error << "Shared boundary id("
10017  << shd_bnd_id_overlap << ")\n";
10018  const unsigned n_v = poly_to_connect_pt->nvertex();
10019  for (unsigned i = 0; i < n_v; i++)
10020  {
10021  Vector<double> cvertex =
10022  poly_to_connect_pt->vertex_coordinate(i);
10023  error
10024  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10025  <<cvertex[1]<<")\n";
10026  }
10027  } // if (poly_to_connect_pt != 0)
10028  } // for (ss < n_shd_bnd_overlap_int_bnd)
10029 
10030  throw OomphLibError(
10031  error.str(),
10032  "TriangleMesh::create_shared_polylines_connections()",
10033  OOMPH_EXCEPTION_LOCATION);
10034  } // if (!found_vertex_index)
10035 #endif
10036 
10037  // Create the connection, the left vertex of the current
10038  // shared boundary is connected with the vertex_index-th
10039  // vertex of sub_poly_to_connect-th subpolyline of the
10040  // destination boundary
10041  shd_poly_pt->connect_initial_vertex_to_polyline(
10042  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10043 
10044  } // else if (!connecting_to_an_overlaped_boundary)
10045 
10046  } // else if (!connecting_to_an_split_boundary)
10047 
10048  } // if (connection_to_the_left != -1)
10049 
10050  // --------------------------------------------------------------
10051  // Connection to the right
10052  if (is_connected_to_the_right)
10053  {
10054  // Get the unsigned version of the bound id to connect to
10055  // the right
10056  const unsigned uconnection_to_the_right =
10057  shd_poly_pt->final_vertex_connected_bnd_id();
10058 
10059  // The pointer to the boundary to connect
10060  TriangleMeshPolyLine *poly_to_connect_pt = 0;
10061 
10062  // Flag to indicate we are trying to connect to an split
10063  // boundary
10064  bool connecting_to_an_split_boundary = false;
10065 
10066  // Flag to indicate we are trying to connecto to an internal
10067  // boundary that is overlaped by a shared boundary
10068  bool connecting_to_an_overlaped_boundary = false;
10069 
10070  // Check if the connection is with itself
10071  if (uconnection_to_the_right == bound_id)
10072  {
10073  // Set the pointer to the polyline to connect
10074  poly_to_connect_pt = shd_poly_pt;
10075  }
10076  else
10077  {
10078  // Get the initial shared boundary ids
10079  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10080  // Check if the boundary to connect is a shared polyline
10081  if (uconnection_to_the_right >= initial_shd_bnd_id)
10082  {
10083  // Get the polyline pointer representing the destination
10084  // boundary
10085  poly_to_connect_pt =
10086  boundary_polyline_pt(uconnection_to_the_right);
10087  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10088  else
10089  {
10090  // If we are going to connect to an original boundary
10091  // verify if the boundary was splitted during the
10092  // distribution process to consider all the chunks
10093  // (sub-polylines) of the boundary
10094  if (boundary_was_splitted(uconnection_to_the_right))
10095  {
10096  connecting_to_an_split_boundary = true;
10097  } // if (boundary_was_splitted(uconnection_to_the_right))
10098 
10099  // If we are going to connect to an original boundary
10100  // verify if the boundary, or any of its chunks is
10101  // marked to be overlapped by a shared boundary, if that
10102  // is the case we first check for connections in the
10103  // shared boundary that overlaps the internal boundary,
10104  // or the chunks, and then check for connections in the
10105  // original boundary
10106  if (connecting_to_an_split_boundary)
10107  {
10108  // Get the number of chucks that represent the
10109  // destination boundary
10110  const unsigned n_sub_poly =
10111  nboundary_subpolylines(uconnection_to_the_right);
10112  // Now loop over the chunks of the destination
10113  // boundary and if any of them is marked to be
10114  // overlaped by a shared boundary then set the flag
10115  // and break the loop
10116  for (unsigned ii =0; ii < n_sub_poly; ii++)
10117  {
10118  if (boundary_marked_as_shared_boundary(
10119  uconnection_to_the_right, ii))
10120  {
10121  // Mark the boundary as being overlaped by a
10122  // shared boundary
10123  connecting_to_an_overlaped_boundary = true;
10124  // Break, no need to look for more overlapings
10125  break;
10126  } // if (boundary_marked_as_shared_boundary(...))
10127  } // for (ii < n_sub_poly)
10128  } // if (connecting_to_an_split_boundary)
10129  else
10130  {
10131  // If not connecting to an split boundary then check
10132  // if the whole destination boundary is overlaped by
10133  // an internal boundary
10134  if (boundary_marked_as_shared_boundary(
10135  uconnection_to_the_right, 0))
10136  {
10137  // Mark the boundary as being overlaped by a shared
10138  // boundary
10139  connecting_to_an_overlaped_boundary = true;
10140  } // if (boundary_marked_as_shared_boundary(...))
10141  } // else if (connecting_to_an_split_boundary)
10142 
10143  // If we are connecting neither to an split boundary nor
10144  // an overlaped boundary then get the pointer to the
10145  // original boundary
10146  if (!(connecting_to_an_split_boundary ||
10147  connecting_to_an_overlaped_boundary))
10148  {
10149  // Get the polyline pointer representing the
10150  // destination boundary
10151  poly_to_connect_pt =
10152  boundary_polyline_pt(uconnection_to_the_right);
10153  } // else if (NOT split, NOT overlaped)
10154  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10155 
10156  } // else if (uconnection_to_the_right == bound_id)
10157 
10158 #ifdef PARANOID
10159  // If we are not connecting to an original boundary
10160  // (connecting to the same shared boundary or to another
10161  // shared boundary) then the boundary should not be marked
10162  // as split
10163  if (!connecting_to_an_split_boundary)
10164  {
10165  if (boundary_was_splitted(uconnection_to_the_right))
10166  {
10167  std::stringstream error;
10168  error
10169  << "The current shared boundary (" << bound_id << ") was "
10170  << "marked to have a connection\nto the right with the "
10171  << "boundary (" << uconnection_to_the_right << ").\n"
10172  << "The problem is that the destination boundary (possibly\n"
10173  << "another shared boundary) is marked to be split\n"
10174  << "There should not be split shared boundaries\n\n";
10175  throw OomphLibError(
10176  error.str(),
10177  "TriangleMesh::create_shared_polylines_connections()",
10178  OOMPH_EXCEPTION_LOCATION);
10179  }
10180  } // if (!connecting_to_an_split_boundary)
10181 #endif
10182 
10183  // Now look for the vertex number on the destination
10184  // boundary(ies) -- in case that the boundary was split ---
10185 
10186  // Do not check for same orientation, that was previously
10187  // worked by interchanging the connections boundaries (if
10188  // necessary)
10189 
10190  // Get the right vertex in the shared boundary
10191  Vector<double> shd_bnd_right_vertex =
10192  shd_poly_pt->vertex_coordinate(n_vertex-1);
10193 
10194  // If the boundary was not split then inmediately look for
10195  // the vertex index in the destination boundary
10196  if (!connecting_to_an_split_boundary)
10197  {
10198  // ... check if the boundary is marked to be overlaped by
10199  // a shared boundary
10200  if (!connecting_to_an_overlaped_boundary)
10201  {
10202  // If that is not the case then we can safely look for
10203  // the vertex number on the destination boundar
10204 
10205  unsigned vertex_index = 0;
10206  const bool found_vertex_index =
10207  get_connected_vertex_number_on_destination_polyline(
10208  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10209 
10210  // If we could not find the vertex index to connect then
10211  // we are in trouble
10212  if (!found_vertex_index)
10213  {
10214  std::stringstream error;
10215  error
10216  << "The current shared boundary (" << bound_id << ") was "
10217  << "marked to have a connection\nto the right with the "
10218  << "boundary (" << uconnection_to_the_right << ").\n"
10219  << "The problem is that the right vertex of the current\n"
10220  << "shared boundary is not in the list of vertices of the\n"
10221  << "boundary to connect.\n\n"
10222  << "This is the right vertex of the current shared boundary\n"
10223  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10224  << shd_bnd_right_vertex[1] << ")\n\n"
10225  << "This is the list of vertices on the destination boundary\n";
10226  const unsigned n_v = poly_to_connect_pt->nvertex();
10227  for (unsigned i = 0; i < n_v; i++)
10228  {
10229  Vector<double> cvertex =
10230  poly_to_connect_pt->vertex_coordinate(i);
10231  error
10232  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
10233  }
10234  throw OomphLibError(
10235  error.str(),
10236  "TriangleMesh::create_shared_polylines_connections()",
10237  OOMPH_EXCEPTION_LOCATION);
10238  } // if (!found_vertex_index)
10239 
10240  // Create the connection, the right vertex of the current
10241  // shared boundary is connected with the vertex_index-th
10242  // vertex on the destination boundary
10243  shd_poly_pt->connect_final_vertex_to_polyline(
10244  poly_to_connect_pt, vertex_index);
10245 
10246  } // if (!connecting_to_an_overlaped_boundary)
10247  else
10248  {
10249  // If the boundary is marked to be overlaped by a shared
10250  // boundary then get that shared boundary and look for
10251  // the connection in that boundary
10252 
10253  // The vertex where to store the index to connect
10254  unsigned vertex_index = 0;
10255  // A flag to indicate if the connection was found
10256  bool found_vertex_index = false;
10257 
10258  // Get the shared boundary id that is overlaping the
10259  // internal boundary
10260  Vector<unsigned> dst_shd_bnd_ids;
10261  get_shared_boundaries_overlapping_internal_boundary(
10262  uconnection_to_the_right, dst_shd_bnd_ids);
10263 
10264  // Get the number of shared polylines that were found to
10265  // overlap the internal boundary
10266  const unsigned n_shd_bnd_overlap_int_bnd =
10267  dst_shd_bnd_ids.size();
10268 
10269  // Loop over the shared boundaries that overlap the
10270  // internal boundary and look for the vertex to connect
10271  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10272  {
10273  // Get the shared polyline
10274  const unsigned new_connection_to_the_right =
10275  dst_shd_bnd_ids[ss];
10276 
10277  // Get the shared polyline that is overlaping the
10278  // internal boundary
10279  poly_to_connect_pt =
10280  boundary_polyline_pt(new_connection_to_the_right);
10281 
10282  if (poly_to_connect_pt!=0)
10283  {
10284  // Look for the vertex number in the destination
10285  // shared polyline
10286  found_vertex_index =
10287  get_connected_vertex_number_on_destination_polyline(
10288  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10289  } // if (poly_to_connect_pt!=0)
10290 
10291  // If we have found the vertex to connect then
10292  // break the loop
10293  if (found_vertex_index)
10294  {
10295  break;
10296  } // if (found_vertex_index)
10297 
10298  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10299 
10300 #ifdef PARANOID
10301  // If we could not find the vertex index to connect then
10302  // we are in trouble
10303  if (!found_vertex_index)
10304  {
10305  std::stringstream error;
10306  error
10307  << "The current shared boundary (" << bound_id << ") was "
10308  << "marked to have a connection\nto the right with the "
10309  << "boundary (" << uconnection_to_the_right << ").\n"
10310  << "This last boundary is marked to be overlaped by "
10311  << "shared boundaries\n"
10312  << "The problem is that the right vertex of the current\n"
10313  << "shared boundary is not in the list of vertices of the\n"
10314  << "boundary to connect.\n\n"
10315  << "This is the right vertex of the current shared boundary\n"
10316  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10317  << shd_bnd_right_vertex[1] << ")\n\n"
10318  << "This is the list of vertices on the destination "
10319  << "boundary\n";
10320  Vector<unsigned> dst_shd_bnd_ids;
10321  get_shared_boundaries_overlapping_internal_boundary(
10322  uconnection_to_the_right, dst_shd_bnd_ids);
10323  const unsigned n_shd_bnd_overlap_int_bnd =
10324  dst_shd_bnd_ids.size();
10325  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10326  {
10327  const unsigned new_connection_to_the_right =
10328  dst_shd_bnd_ids[ss];
10329  poly_to_connect_pt =
10330  boundary_polyline_pt(new_connection_to_the_right);
10331  if (poly_to_connect_pt != 0)
10332  {
10333  const unsigned shd_bnd_id_overlap =
10334  poly_to_connect_pt->boundary_id();
10335  error << "Shared boundary id("
10336  << shd_bnd_id_overlap << ")\n";
10337  const unsigned n_v = poly_to_connect_pt->nvertex();
10338  for (unsigned i = 0; i < n_v; i++)
10339  {
10340  Vector<double> cvertex =
10341  poly_to_connect_pt->vertex_coordinate(i);
10342  error
10343  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10344  <<cvertex[1]<<")\n";
10345  }
10346  } // if (poly_to_connect_pt != 0)
10347  } // for (ss < n_shd_bnd_overlap_int_bnd)
10348 
10349  throw OomphLibError(
10350  error.str(),
10351  "TriangleMesh::create_shared_polylines_connections()",
10352  OOMPH_EXCEPTION_LOCATION);
10353 
10354  } // if (!found_vertex_index)
10355 #endif
10356 
10357  // Create the connection, the right vertex of the
10358  // current shared boundary is connected with the
10359  // vertex_index-th vertex on the destination boundary
10360  shd_poly_pt->connect_final_vertex_to_polyline(
10361  poly_to_connect_pt, vertex_index);
10362 
10363  } // else if (!connecting_to_an_overlaped_boundary)
10364 
10365  } // if (!connecting_to_an_split_boundary)
10366  else
10367  {
10368  // If the boundary was split then we need to look for the
10369  // vertex in the sub-polylines
10370 
10371  // Get the sub-polylines vector
10372  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10373  boundary_subpolylines(uconnection_to_the_right);
10374 
10375  // Get the number of sub-polylines
10376  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10377 #ifdef PARANOID
10378  if (nsub_poly <= 1)
10379  {
10380  std::ostringstream error_message;
10381  error_message
10382  <<"The boundary (" << uconnection_to_the_right << ") was "
10383  << "marked to be splitted but\n"
10384  << "there are only ("<<nsub_poly<<") polylines to "
10385  << "represent it.\n";
10386  throw OomphLibError(
10387  error_message.str(),
10388  "TriangleMesh::create_shared_polylines_connections()",
10389  OOMPH_EXCEPTION_LOCATION);
10390  } // if (nsub_poly <= 1)
10391 #endif
10392 
10393  // We need to check if the boundary is marked to be
10394  // overlaped by an internal boundary, if that is the case
10395  // we need to check for each indivual subpolyline, and for
10396  // those overlaped by a shared polyline look for the
10397  // vertex in the shared polyline representation instead of
10398  // the original subpolyline
10399 
10400  // ... check if the boundary is marked to be overlaped by
10401  // a shared boundary
10402  if (!connecting_to_an_overlaped_boundary)
10403  {
10404  // We can work without checking the subpolylines
10405  // individually
10406 
10407  // The vertex where to store the index to connect
10408  unsigned vertex_index = 0;
10409  // The subpoly number to connect
10410  unsigned sub_poly_to_connect = 0;
10411  // A flag to indicate if the connection was found
10412  bool found_vertex_index = false;
10413 
10414  // Look for the vertex number to connect on each of the
10415  // subpolyines
10416  for (unsigned isub = 0; isub < nsub_poly; isub++)
10417  {
10418  // Assign the pointer to the sub-polyline
10419  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10420  // Search for the vertex in the current sub-polyline
10421  found_vertex_index =
10422  get_connected_vertex_number_on_destination_polyline(
10423  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10424  // If we have found the vertex to connect then break the
10425  // loop
10426  if (found_vertex_index)
10427  {
10428  // But first save the subpoly number (chunk), that
10429  // will be used to perform the connection
10430  sub_poly_to_connect = isub;
10431  break;
10432  } // if (found_vertex_index)
10433  } // for (isub < nsub_poly)
10434 
10435 #ifdef PARANOID
10436  // If we could not find the vertex index to connect then
10437  // we are in trouble
10438  if (!found_vertex_index)
10439  {
10440  std::stringstream error;
10441  error
10442  << "The current shared boundary (" << bound_id << ") was "
10443  << "marked to have a connection\nto the right with the "
10444  << "boundary (" << uconnection_to_the_right << ").\n"
10445  << "The problem is that the right vertex of the current\n"
10446  << "shared boundary is not in the list of vertices of any\n"
10447  << "of the sub polylines that represent the boundary to\n"
10448  << "connect.\n\n"
10449  << "This is the right vertex of the current shared boundary\n"
10450  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10451  << shd_bnd_right_vertex[1] << ")\n\n"
10452  << "This is the list of vertices on the destination "
10453  << "boundary\n";
10454  for (unsigned p = 0; p < nsub_poly; p++)
10455  {
10456  error << "Subpolyline #("<< p << ")\n";
10457  poly_to_connect_pt = tmp_vector_subpolylines[p];
10458  const unsigned n_v = poly_to_connect_pt->nvertex();
10459  for (unsigned i = 0; i < n_v; i++)
10460  {
10461  Vector<double> cvertex =
10462  poly_to_connect_pt->vertex_coordinate(i);
10463  error
10464  <<"Vertex #"<<i<<": ("<<cvertex[0]
10465  <<", "<<cvertex[1]<<")\n";
10466  }
10467  } // for (p < nsub_poly)
10468  throw OomphLibError(
10469  error.str(),
10470  "TriangleMesh::create_shared_polylines_connections()",
10471  OOMPH_EXCEPTION_LOCATION);
10472  } // if (!found_vertex_index)
10473 #endif
10474 
10475  // Create the connection, the right vertex of the current
10476  // shared boundary is connected with the vertex_index-th
10477  // vertex of sub_poly_to_connect-th subpolyline of the
10478  // destination boundary
10479  shd_poly_pt->connect_final_vertex_to_polyline(
10480  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10481 
10482  } // if (!connecting_to_an_overlaped_boundary)
10483  else
10484  {
10485  // We first look on the shared boundaries that overlap
10486  // the internal boundaries and the look for the
10487  // sub-polylines that are not marked as being overlaped
10488  // by shared boundaries
10489 
10490  // The vertex where to store the index to connect
10491  unsigned vertex_index = 0;
10492  // The subpoly number to connect
10493  unsigned sub_poly_to_connect = 0;
10494  // A flag to indicate if the connection was found
10495  bool found_vertex_index = false;
10496 
10497  // Get the shared boundaries id that are overlaping the
10498  // internal boundary
10499  Vector<unsigned> dst_shd_bnd_ids;
10500  get_shared_boundaries_overlapping_internal_boundary(
10501  uconnection_to_the_right, dst_shd_bnd_ids);
10502 
10503  // Get the number of shared polylines that were found to
10504  // overlap the internal boundary
10505  const unsigned n_shd_bnd_overlap_int_bnd =
10506  dst_shd_bnd_ids.size();
10507 
10508  // Loop over the shared boundaries that overlap the
10509  // internal boundary and look for the vertex to connect
10510  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10511  {
10512  // Get the shared polyline
10513  const unsigned new_connection_to_the_right =
10514  dst_shd_bnd_ids[ss];
10515 
10516  // Make sure that the destination polyline is not the
10517  // same as the current shared polyline
10518  if (bound_id != new_connection_to_the_right)
10519  {
10520  // Get the shared polyline that is overlaping the
10521  // internal boundary
10522  poly_to_connect_pt =
10523  boundary_polyline_pt(new_connection_to_the_right);
10524 
10525  if (poly_to_connect_pt != 0)
10526  {
10527  // Look for the vertex number in the destination
10528  // shared polyline
10529  found_vertex_index =
10530  get_connected_vertex_number_on_destination_polyline(
10531  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10532  } // if (poly_to_connect_pt != 0)
10533 
10534  // If we have found the vertex to connect then
10535  // break the loop
10536  if (found_vertex_index)
10537  {
10538  break;
10539  } // if (found_vertex_index)
10540 
10541  } // if (bound_id != new_connection_to_the_right)
10542 
10543  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10544 
10545  // If we have not yet found the vertex then look for it
10546  // in the sub-polylines that are not overlaped by shared
10547  // boundaries
10548  if (!found_vertex_index)
10549  {
10550  // Look for the vertex number to connect on each of
10551  // the subpolyines
10552  for (unsigned isub = 0; isub < nsub_poly; isub++)
10553  {
10554  // Only work with those sub-polylines that are not
10555  // overlaped by shared boundaries
10556  if (!boundary_marked_as_shared_boundary(
10557  uconnection_to_the_right, isub))
10558  {
10559  // Assign the pointer to the sub-polyline
10560  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10561  // Search for the vertex in the current sub-polyline
10562  found_vertex_index =
10563  get_connected_vertex_number_on_destination_polyline(
10564  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10565  // If we have found the vertex to connect then break the
10566  // loop
10567  if (found_vertex_index)
10568  {
10569  // But first save the subpoly number (chunk), that
10570  // will be used to perform the connection
10571  sub_poly_to_connect = isub;
10572  break;
10573  } // if (found_vertex_index)
10574 
10575  } // if (not overlaped by shared boundary)
10576 
10577  } // for (isub < nsub_poly)
10578 
10579  } // if (!found_vertex_index)
10580 
10581 #ifdef PARANOID
10582  // If we could not find the vertex index to connect then
10583  // we are in trouble
10584  if (!found_vertex_index)
10585  {
10586  std::stringstream error;
10587  error
10588  << "The current shared boundary (" << bound_id << ") was "
10589  << "marked to have a connection\nto the right with the "
10590  << "boundary (" << uconnection_to_the_right << ").\n"
10591  << "This last boundary is marked to be overlaped by "
10592  << "shared boundaries\n"
10593  << "The problem is that the right vertex of the current\n"
10594  << "shared boundary is not in the list of vertices of "
10595  << "the\nboundary to connect.\n\n"
10596  << "This is the right vertex of the current shared "
10597  << "boundary\n"
10598  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10599  << shd_bnd_right_vertex[1] << ")\n\n"
10600  << "This is the list of vertices on the destination "
10601  << "boundary (only those subpolylines not marked as "
10602  << "overlaped by\nshared boundaries)\n";
10603  for (unsigned p = 0; p < nsub_poly; p++)
10604  {
10605  if (!boundary_marked_as_shared_boundary(
10606  uconnection_to_the_right, p))
10607  {
10608  error << "Subpolyline #("<< p << ")\n";
10609  poly_to_connect_pt = tmp_vector_subpolylines[p];
10610  const unsigned n_v = poly_to_connect_pt->nvertex();
10611  for (unsigned i = 0; i < n_v; i++)
10612  {
10613  Vector<double> cvertex =
10614  poly_to_connect_pt->vertex_coordinate(i);
10615  error
10616  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10617  <<cvertex[1]<<")\n";
10618  }
10619  } // Not marked as overlaped
10620  } // for (p < nsub_poly)
10621  error << "\nThis is the list of vertices of the shared "
10622  << "polylines that overlap\nthe internal "
10623  << "boundary\n";
10624  Vector<unsigned> dst_shd_bnd_ids;
10625  get_shared_boundaries_overlapping_internal_boundary(
10626  uconnection_to_the_right, dst_shd_bnd_ids);
10627  const unsigned n_shd_bnd_overlap_int_bnd =
10628  dst_shd_bnd_ids.size();
10629  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10630  {
10631  const unsigned new_connection_to_the_right =
10632  dst_shd_bnd_ids[ss];
10633  poly_to_connect_pt =
10634  boundary_polyline_pt(new_connection_to_the_right);
10635  if (poly_to_connect_pt != 0)
10636  {
10637  const unsigned shd_bnd_id_overlap =
10638  poly_to_connect_pt->boundary_id();
10639  error << "Shared boundary id("
10640  << shd_bnd_id_overlap << ")\n";
10641  const unsigned n_v = poly_to_connect_pt->nvertex();
10642  for (unsigned i = 0; i < n_v; i++)
10643  {
10644  Vector<double> cvertex =
10645  poly_to_connect_pt->vertex_coordinate(i);
10646  error
10647  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10648  <<cvertex[1]<<")\n";
10649  }
10650  } // if (poly_to_connect_pt != 0)
10651  } // for (ss < n_shd_bnd_overlap_int_bnd)
10652 
10653  throw OomphLibError(
10654  error.str(),
10655  "TriangleMesh::create_shared_polylines_connections()",
10656  OOMPH_EXCEPTION_LOCATION);
10657  } // if (!found_vertex_index)
10658 #endif
10659 
10660  // Create the connection, the left vertex of the current
10661  // shared boundary is connected with the vertex_index-th
10662  // vertex of sub_poly_to_connect-th subpolyline of the
10663  // destination boundary
10664  shd_poly_pt->connect_final_vertex_to_polyline(
10665  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10666 
10667  } // else if (!connecting_to_an_overlaped_boundary)
10668 
10669  } // else if (!connecting_to_an_split_boundary)
10670 
10671  } // if (connection_to_the_right != -1)
10672 
10673  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10674 
10675  } // for (ipoly < npoly)
10676 
10677  } // for (icurve < ncurves)
10678 
10679  }
10680 
10681  //=======================================================================
10682  // \short Compute the holes left by the halo elements, those adjacent
10683  // to the shared boundaries
10684  //=======================================================================
10685  template<class ELEMENT>
10687  Vector<Vector<double> > &output_holes_coordinates)
10688  {
10689  // Storage for number of processors and current processor
10690  const unsigned n_proc = this->communicator_pt()->nproc();
10691  const unsigned my_rank = this->communicator_pt()->my_rank();
10692 
10693  // Mark those done elements, so we do not repeat any coordinate left
10694  // by repeated halo elements
10695  std::map<FiniteElement*, bool> done_ele;
10696 
10697  // Loop over the processors and get the shared boundaries ids that
10698  // the current processor has with the other processors
10699  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10700  {
10701  // There are shared boundaries only with the other processors
10702  if (iproc != my_rank)
10703  {
10704  // Get the number of shared boundaries with the iproc
10705  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10706 
10707 #ifdef PARANOID
10708  // Get the number of shared boundaries with the iproc, but
10709  // reversing the indexes
10710  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10711  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10712  {
10713  std::ostringstream error_stream;
10714  error_stream
10715  << "The number of shared boundaries of processor ("
10716  << my_rank << ") with processor(" << iproc << "): ("
10717  << n_shd_bnd_iproc << ")\n"
10718  << "is different from the number of shared boundaries of "
10719  << "processor (" << iproc << ")\nwith processor ("
10720  << my_rank << "): (" << n_shd_bnd_iproc << ")\n\n";
10721  throw OomphLibError(error_stream.str(),
10722  OOMPH_CURRENT_FUNCTION,
10723  OOMPH_EXCEPTION_LOCATION);
10724 
10725  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10726 #endif
10727 
10728  // Loop over the shared boundaries ids
10729  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10730  {
10731  // Get the shared boundary id
10732  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10733 
10734  // Get the number of shared boundary elements
10735  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10736 
10737  // Loop over the shared boundary elements
10738  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10739  {
10740  // Get the shared boundary element
10741  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10742 
10743  // Only work with halo elements
10744  if (ele_pt->is_halo())
10745  {
10746  // If the element has not been visited
10747  if (!done_ele[ele_pt])
10748  {
10749  // Get the number of nodes
10750  const unsigned n_nodes = ele_pt->nnode();
10751 
10752  // Compute the centroid of the element
10753  Vector<double> element_centroid(2, 0.0);
10754  // Loop over the nodes
10755  for (unsigned k = 0; k < n_nodes; k++)
10756  {
10757  Node* tmp_node_pt = ele_pt->node_pt(k);
10758  // Loop over the dimension
10759  for (unsigned d = 0; d < 2; d++)
10760  {
10761  element_centroid[d]+=tmp_node_pt->x(d);
10762  } // for (d < 2)
10763  } // for (k < n_nodes)
10764 
10765  // Average the data
10766  for (unsigned d = 0; d < 2; d++)
10767  {
10768  element_centroid[d] =
10769  element_centroid[d] / (double)n_nodes;
10770  } // for (d < 2)
10771 
10772  // Add the centroid to the output holes
10773  output_holes_coordinates.push_back(element_centroid);
10774 
10775  } // if (!done_ele[ele_pt])
10776 
10777  } // if (ele_pt->is_halo())
10778 
10779  } // for1 (e < n_shd_bnd_ele)
10780 
10781  } // for (i < n_shd_bnd_iproc)
10782 
10783  } // if (iproc != my_rank)
10784 
10785  } // for (iproc < n_proc)
10786 
10787  }
10788 
10789  //======================================================================
10790  // \short Keeps those vertices that define a hole, those that are
10791  // inside closed internal boundaries in the new polygons that define
10792  // the domain. Delete those outside/inside the outer polygons (this
10793  // is required since Triangle can not deal with vertices that define
10794  // holes outside the new outer polygons of the domain)
10795  //======================================================================
10796  template<class ELEMENT>
10798  Vector<TriangleMeshPolygon *> &polygons_pt,
10799  Vector<Vector<double> > &output_holes_coordinates)
10800  {
10801  // General strategy
10802 
10803  // 1) Identify the inner closed boundaries
10804 
10805  // 2) Separate the vertices in three groups
10806 
10807  // --- 2.1) The vertices inside the inner closed boundaries, these
10808  // are not deleted because they define holes
10809 
10810  // --- 2.2) The vertices outside the outer boundaries, these are
10811  // deleted only if they are outside the convex hull defined
10812  // by all the polygons
10813 
10814  // --- 2.3) Any other vertex is deleted
10815 
10816  // Get the number of input holes
10817  const unsigned n_input_holes = output_holes_coordinates.size();
10818 
10819  // Only do something if there are holes
10820  if (n_input_holes == 0)
10821  {
10822  return;
10823  }
10824 
10825  // Get the number of input polygons
10826  const unsigned n_polygons = polygons_pt.size();
10827 
10828  // Store the vertices of all the input polygons
10829  // vertices_polygons[x][ ][ ]: Polygon number
10830  // vertices_polygons[ ][x][ ]: Vertex number
10831  // vertices_polygons[ ][ ][x]: Vertex coordinate
10832  Vector<Vector<Vector<double> > > vertices_polygons(n_polygons);
10833 
10834  // Loop over all the polygons and get the vertices
10835  for (unsigned p = 0; p < n_polygons; p++)
10836  {
10837  // Get the number of polylines associated to the polygon
10838  const unsigned n_polylines = polygons_pt[p]->npolyline();
10839  // Loop over the polylines and get the vertices
10840  for (unsigned pp = 0; pp < n_polylines; pp++)
10841  {
10842  // Get the polyline
10843  const TriangleMeshPolyLine* tmp_poly_pt =
10844  polygons_pt[p]->polyline_pt(pp);
10845  // Get the number of vertices in the polyline
10846  const unsigned n_vertices = tmp_poly_pt->nvertex();
10847  // Loop over the vertices but only add (n_vertices-1) vertices,
10848  // the last vertex of polyline (pp) is the first vertex of
10849  // polyline (pp+1)
10850  for (unsigned v = 0; v < n_vertices-1; v++)
10851  {
10852  // Get the current vertex
10853  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10854  vertices_polygons[p].push_back(current_vertex);
10855  } // for (v < nvertex)
10856  } // for (p < nouter_polylines)
10857  } // for (p < n_polygons)
10858 
10859  // -------------------------------------------------------------------
10860  // 1) Identify the inner closed boundaries
10861  // -------------------------------------------------------------------
10862 
10863  // A container that indicates if a given polygon should be
10864  // considered as an outer or as an inner polygon. By default all the
10865  // polygons are considered as outer polygons
10866  std::vector<bool> is_outer_polygon(n_polygons, true);
10867 
10868  // We only check for innner polygons if there are more than one
10869  // polygon
10870  if (n_polygons > 1)
10871  {
10872  // Propose an inner polygon, if one of the middle points of its
10873  // edges lies inside any other polygon then the proposed inner
10874  // polygon is marked as an internal polygon
10875 
10876  // Pre-compute the middle points of the edges in the polygons
10877  Vector<Vector<Vector<double> > > polygon_edge_middle_vertex(n_polygons);
10878 
10879  for (unsigned p = 0; p < n_polygons; p++)
10880  {
10881  // Temporary store the vertices of the proposed inner polygon
10882  Vector<Vector<double> > tmp_inner_polygon = vertices_polygons[p];
10883 
10884  // Get the number of vertices in the current proposed inner polygon
10885  const unsigned n_vertices = tmp_inner_polygon.size();
10886 
10887  // Resize with the number of edges in the polygon
10888  polygon_edge_middle_vertex[p].resize(n_vertices-1);
10889 
10890  // Loop over the vertices and compute the middle point in the edge
10891  // that joins each pair of contiguous vertices
10892  for (unsigned e = 0; e < n_vertices - 1; e++)
10893  {
10894  // The dimension
10895  const unsigned dim = 2;
10896  polygon_edge_middle_vertex[p][e].resize(dim);
10897  for (unsigned d = 0; d < dim; d++)
10898  {
10899  polygon_edge_middle_vertex[p][e][d] =
10900  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e+1][d]) / 2.0;
10901  } // for (d < 2)
10902 
10903  } // for (e < n_vertices - 1)
10904 
10905  } // for (p < n_polygons)
10906 
10907  // Loop over the polygons and for every loop propose a different
10908  // inner polygon
10909  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
10910  {
10911  // Flag to indicate that ONE of the middle edge vertices of the
10912  // proposed inner polygon is inside another polygon, this will
10913  // set the proposed inner polygon as an actual inner polygon
10914  bool is_inner_polygon = false;
10915 
10916  // Loop over all the polygons, except the proposed one and check
10917  // if all the middle edges of its edges are inside any other
10918  // polygon
10919  for (unsigned i = 0; i < n_polygons; i++)
10920  {
10921  // Do not check with the polygon itself
10922  if (i != idx_inner)
10923  {
10924  // Get the number of edges of the proposed inner polygon
10925  const unsigned n_edges =
10926  polygon_edge_middle_vertex[idx_inner].size();
10927  // Loop over the middle points in the edges of the current
10928  // proposed inner polygon
10929  for (unsigned e = 0; e < n_edges; e++)
10930  {
10931  // Get the vertex in the current proposed inner polygon
10932  Vector<double> current_vertex =
10933  polygon_edge_middle_vertex[idx_inner][e];
10934  // Check if the current vertex is inside the current i-th
10935  // polygon
10936  const bool is_point_inside =
10937  is_point_inside_polygon_helper(vertices_polygons[i],
10938  current_vertex);
10939 
10940  // If one point is inside then the polygon is inside the
10941  // i-th polygon
10942  if (is_point_inside)
10943  {
10944  // The polygon is an inner polygon
10945  is_inner_polygon = true;
10946  // Break the loop
10947  break;
10948  } // if (is_point_inside)
10949 
10950  } // for (e < n_edges)
10951 
10952  } // if (i != idx_inner)
10953 
10954  // Are all the vertices of the current proposed inner polygon
10955  // inside the i-th polygon
10956  if (is_inner_polygon)
10957  {
10958  // The current proposed inner polygon is an actual inner
10959  // polygon, and is inside the i-th polygon
10960  break;
10961  }
10962 
10963  } // for (i < n_polygons)
10964 
10965  // Is the current proposed inner polygon an actual inner polygon
10966  if (is_inner_polygon)
10967  {
10968  // The current proposed inner polygon is a real inner polygon
10969  is_outer_polygon[idx_inner] = false;
10970  }
10971  else
10972  {
10973  // The current proposed inner polygon IS NOT a real inner
10974  // polygon
10975  is_outer_polygon[idx_inner] = true;
10976  }
10977 
10978  } // for (idx_outer < npolygons)
10979 
10980  } // if (n_polygons > 1)
10981 
10982  // Count the number of outer closed boundaries and inner closed
10983  // boundaries
10984  unsigned n_outer_polygons = 0;
10985  unsigned n_inner_polygons = 0;
10986  // Also get the indexes of the inner polygons
10987  Vector<unsigned> index_inner_polygon;
10988  // Loop over the polygons
10989  for (unsigned i = 0; i < n_polygons; i++)
10990  {
10991  if (is_outer_polygon[i])
10992  {
10993  // Increase the counter for outer polygons
10994  n_outer_polygons++;
10995  }
10996  else
10997  {
10998  // Increase the counter for inner polygons
10999  n_inner_polygons++;
11000  // Store the index of the inner polygon
11001  index_inner_polygon.push_back(i);
11002  }
11003  } // for (i < n_polygons)
11004 
11005  // -------------------------------------------------------------------
11006  // 2) Separate the vertices in three groups
11007 
11008  // --- 2.1) The vertices inside the inner closed boundaries, these are
11009  // not deleted because they define holes
11010 
11011  // --- 2.2) The vertices outside the outer boundaries, these are
11012  // deleted only if they are outside the convex hull defined
11013  // by all the polygons
11014 
11015  // --- 2.3) Any other vertex is deleted
11016  // -------------------------------------------------------------------
11017 
11018  // Keep track of the vertices inside the inner closed boundaries (by
11019  // default all vertices not inside the inner polygons)
11020  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11021 
11022  // Keep track of the vertices outside the outer closed boundaries
11023  // (by default all the vertices are outside the outer polygons)
11024  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11025 
11026  // Keep track of the vertices inside the convex hull (by default
11027  // all the vertices are not inside the convex hull)
11028  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11029 
11030  // Mark the vertices inside the inner closed boundaries
11031  Vector<Vector<Vector<double> > >
11032  vertex_inside_inner_polygon(n_inner_polygons);
11033 
11034  // -------------------------------------------------------------------
11035  // Loop over the inner polygons and find all the vertices inside
11036  // each one
11037  for (unsigned i = 0; i < n_inner_polygons; i++)
11038  {
11039  // Get the vertex of the inner polygon
11040  const unsigned ii = index_inner_polygon[i];
11041  // Loop over the vertices defining holes, mark and store those
11042  // inside the inner polygon
11043  for (unsigned h = 0; h < n_input_holes; h++)
11044  {
11045  // Check if the vertex has not been already marked as inside
11046  // another polygon
11047  if (!is_inside_an_inner_polygon[h])
11048  {
11049  // Check if the hole is inside the current inner polygon
11050  const bool is_inside_polygon =
11051  is_point_inside_polygon_helper(vertices_polygons[ii],
11052  output_holes_coordinates[h]);
11053 
11054  // If the vertex is inside the current inner polygon then mark
11055  // it and associate the vertices to the current inner polygon
11056  if (is_inside_polygon)
11057  {
11058  // Set as inside an inner polygon
11059  is_inside_an_inner_polygon[h] = true;
11060  // Associate the vertex to the current inner polygon
11061  vertex_inside_inner_polygon[i].
11062  push_back(output_holes_coordinates[h]);
11063  } // if (is_inside_polygon)
11064 
11065  } // if (!is_inside_an_inner_polygon[h])
11066 
11067  } // for (h < n_input_holes)
11068 
11069  } // for (i < n_polygons)
11070 
11071  // -------------------------------------------------------------------
11072  // Loop over the vertices defining holes and mark those as outside the
11073  // outer polygons
11074  for (unsigned h = 0; h < n_input_holes; h++)
11075  {
11076  // Check if the vertex has not been already marked as inside
11077  // another polygon
11078  if (!is_inside_an_inner_polygon[h])
11079  {
11080  // Loop over the polygons and check if the vertex is outside ALL
11081  // the outer polygons
11082  for (unsigned i = 0; i < n_polygons; i++)
11083  {
11084  // Only work with outer polygons
11085  if (is_outer_polygon[i])
11086  {
11087  // Check if the hole is inside the current outer polygon
11088  const bool is_inside_polygon =
11089  is_point_inside_polygon_helper(vertices_polygons[i],
11090  output_holes_coordinates[h]);
11091 
11092  // If the vertex is inside the current outer polygon then
11093  // mark it and break the loop (it is not outside ALL the
11094  // polygons)
11095  if (is_inside_polygon)
11096  {
11097  // Set as inside an outer polygon
11098  is_outside_the_outer_polygons[h] = false;
11099  // Break the loop
11100  break;
11101  } // if (is_inside_polygon)
11102 
11103  } // if (is_outer_polygon[i])
11104 
11105  } // for (i < n_polygons)
11106 
11107  } // if (!is_inside_an_inner_polygon[h])
11108  else
11109  {
11110  // If the vertex is inside an inner polygon then it is inside an
11111  // outer polygon
11112  is_outside_the_outer_polygons[h] = false;
11113  } // else if (!is_inside_an_inner_polygon[h])
11114 
11115  } // for (h < n_input_holes)
11116 
11117  // -------------------------------------------------------------------
11118  // Compute the convex hull Create the data structure
11119  std::vector<Point> input_vertices_convex_hull;
11120  // Copy ALL the vertices of the polygons
11121  // Loop over the polygons
11122  for (unsigned p = 0; p < n_polygons; p++)
11123  {
11124  // Get the number of vertices
11125  const unsigned n_vertices = vertices_polygons[p].size();
11126  // Loop over the vertices in the polygon
11127  for (unsigned v = 0; v < n_vertices; v++)
11128  {
11129  // Create a new "Point" to store in the input vertices
11130  Point point;
11131  // Assign the values to the "Point"
11132  point.x = vertices_polygons[p][v][0];
11133  point.y = vertices_polygons[p][v][1];
11134  // Add the "Point" to the input vertices
11135  input_vertices_convex_hull.push_back(point);
11136  } // for (v < n_vertices)
11137  } // for (p < n_polygons)
11138 
11139  // Compute the convex hull
11140  std::vector<Point> output_vertices_convex_hull =
11141  convex_hull(input_vertices_convex_hull);
11142 
11143  // Get the number of vertices in the convex hull
11144  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11145 
11146  // Copy the output to the used data structures
11147  Vector<Vector<double> > vertices_convex_hull(n_vertices_convex_hull);
11148  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11149  {
11150  // Resize the data structure
11151  vertices_convex_hull[i].resize(2);
11152  // Copy the data
11153  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11154  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11155  } // for (i < n_vertices_convex_hull)
11156 
11157  // Loop over the vertices defining holes, work only with those
11158  // outside ALL the outer boundaries and mark those inside the convex
11159  // hull
11160  for (unsigned h = 0; h < n_input_holes; h++)
11161  {
11162  // Only work with those outside ALL the outer polygons
11163  if (is_outside_the_outer_polygons[h])
11164  {
11165  // Check if the hole is inside the convex hull
11166  const bool is_inside_convex_hull =
11167  is_point_inside_polygon_helper(vertices_convex_hull,
11168  output_holes_coordinates[h]);
11169 
11170  // If the vertex is inside the convex hull then mark it
11171  if (is_inside_convex_hull)
11172  {
11173  // Set as inside the convex hull
11174  is_inside_the_convex_hull[h] = true;
11175  } // if (is_inside_convex_hull)
11176 
11177  } // if (is_outside_the_outer_polygons[h])
11178  else
11179  {
11180  // Any vertex inside any outer polygon is inside the convex hull
11181  is_inside_the_convex_hull[h] = true;
11182  } // else if (is_outside_the_outer_polygons[h])
11183 
11184  } // for (h < n_input_holes)
11185 
11186  // Store the output holes, only (those inside an inner polygon) OR
11187  // (those outside ALL the polygons AND inside the convex hull)
11188  Vector<Vector<double> > hole_kept;
11189  for (unsigned h = 0; h < n_input_holes; h++)
11190  {
11191  // Check if the hole should be kept
11192  if ((is_inside_an_inner_polygon[h]) ||
11193  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11194  {
11195  // Copy the hole information
11196  hole_kept.push_back(output_holes_coordinates[h]);
11197  } // if (keep_hole[h])
11198  } // for (h < n_input_holes)
11199 
11200  // Clear the previous storage
11201  output_holes_coordinates.clear();
11202  // Set the output holes
11203  output_holes_coordinates = hole_kept;
11204 
11205  }
11206 
11207  //======================================================================
11208  // \short Sorts the polylines so they be contiguous and then we can
11209  // create a closed or open curve from them
11210  //======================================================================
11211  template<class ELEMENT>
11213  sort_polylines_helper(Vector<TriangleMeshPolyLine *>
11214  &unsorted_polylines_pt,
11215  Vector<Vector<TriangleMeshPolyLine *> >
11216  &sorted_polylines_pt)
11217  {
11218  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11219  unsigned n_sorted_polylines = 0;
11220  unsigned curves_index = 0;
11221 
11222  // Map to know which polyline has been already sorted
11223  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11224 
11225  do
11226  {
11227  // Create the list that stores the polylines and allows to introduce
11228  // polylines to the left and to the right
11229  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11230  bool changes = false;
11231 
11232  // Create pointers to the left and right "side" of the sorted list of
11233  // new created TriangleMeshPolyLines
11234  TriangleMeshPolyLine* left_pt = 0;
11235  TriangleMeshPolyLine* right_pt = 0;
11236 
11237  // 1) Take the first non done polyline on the unsorted list of polylines
11238  unsigned pp = 0;
11239  bool found_root_polyline = false;
11240  while (pp < n_unsorted_polylines && !found_root_polyline)
11241  {
11242  if (!done_polyline[unsorted_polylines_pt[pp]])
11243  {found_root_polyline = true;}
11244  else
11245  {pp++;}
11246  }
11247 
11248  // Check if there are polylines to be sorted
11249  if (pp < n_unsorted_polylines)
11250  {
11251  // 2) Mark the polyline as done
11252  left_pt = right_pt = unsorted_polylines_pt[pp];
11253  done_polyline[left_pt] = true;
11254  // Increment the number of sorted polylines
11255  n_sorted_polylines++;
11256 
11257  // 3) Add this polyline to the sorted list and use it as root
11258  // to sort the other polylines
11259  sorted_polyline_list_pt.push_back(left_pt);
11260 
11261  do {
11262 
11263  changes = false;
11264 
11265  Vector<double> left_vertex(2);
11266  Vector<double> right_vertex(2);
11267 
11268  left_pt->initial_vertex_coordinate(left_vertex);
11269  right_pt->final_vertex_coordinate(right_vertex);
11270 
11271  for (unsigned i = pp+1; i < n_unsorted_polylines; i++)
11272  {
11273  TriangleMeshPolyLine *current_polyline_pt =
11274  unsorted_polylines_pt[i];
11275  if (!done_polyline[current_polyline_pt])
11276  {
11277  Vector<double> initial_vertex(2);
11278  Vector<double> final_vertex(2);
11279  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11280  current_polyline_pt->final_vertex_coordinate(final_vertex);
11281 
11282  // Compare if the current polyline should go to the left or
11283  // to the right on the sorted polyline list
11284 
11285  // Go to the left
11286  if (left_vertex == final_vertex)
11287  {
11288  left_pt = current_polyline_pt;
11289  sorted_polyline_list_pt.push_front(left_pt);
11290  done_polyline[left_pt] = true;
11291  n_sorted_polylines++;
11292 
11293  // We have added one more polyline, go for another round
11294  changes = true;
11295  }
11296  // Go to the right
11297  else if (right_vertex == initial_vertex)
11298  {
11299  right_pt = current_polyline_pt;
11300  sorted_polyline_list_pt.push_back(right_pt);
11301  done_polyline[right_pt] = true;
11302  n_sorted_polylines++;
11303 
11304  // We have added one more polyline, go for another round
11305  changes = true;
11306  }
11307  // Go to the left but it is reversed
11308  else if (left_vertex == initial_vertex)
11309  {
11310  current_polyline_pt->reverse();
11311  left_pt = current_polyline_pt;
11312  sorted_polyline_list_pt.push_front(left_pt);
11313  done_polyline[left_pt] = true;
11314  n_sorted_polylines++;
11315 
11316  // We have added one more polyline, go for another round
11317  changes = true;
11318  }
11319  // Go to the right but it is reversed
11320  else if (right_vertex == final_vertex)
11321  {
11322  current_polyline_pt->reverse();
11323  right_pt = current_polyline_pt;
11324  sorted_polyline_list_pt.push_back(right_pt);
11325  done_polyline[right_pt] = true;
11326  n_sorted_polylines++;
11327 
11328  // We have added one more polyline, go for another round
11329  changes = true;
11330  }
11331  } // if (!done_polyline[current_polyline_pt])
11332  if (changes) {break;}
11333  } // for (i < n_unsorted_polylines)
11334  }while(changes);
11335 
11336  } // if (pp < n_unsorted_polylines)
11337  else
11338  {
11339  // All the polylines are now on the sorted list of polylines
11340 #ifdef PARANOID
11341  // This case comes when it was not possible to find a root polyline
11342  // since all of them are marked as done but the number of sorted and
11343  // unsorted polylines is not the same
11344  if (!found_root_polyline)
11345  {
11346  std::stringstream err;
11347  err << "It was not possible to find a root polyline to sort the "
11348  << "others around it.\nThe number of unsorted and sorted "
11349  << "polylines is different, it means that\nnot all the "
11350  << "polylines have been sorted.\n"
11351  << "Found root polyline: ("<<found_root_polyline<<")\n"
11352  << "Sorted polylines: ("<<n_sorted_polylines<<")\n"
11353  << "Unsorted polylines: ("<<n_unsorted_polylines<<")\n";
11354  throw OomphLibError(err.str(),"TriangleMesh::sort_polylines_helper()",
11355  OOMPH_EXCEPTION_LOCATION);
11356  }
11357 #endif
11358  }
11359 
11360  // Create the storage for the new sorted polylines and copy them on the
11361  // vector structure for sorted polylines
11362  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11363 
11364  // Create the temporal vector that stores the sorted polylines
11365  Vector<TriangleMeshPolyLine *>
11366  tmp_sorted_polylines(n_sorted_polyline_on_list);
11367  unsigned counter = 0;
11368 
11369  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11370  for (it_polyline = sorted_polyline_list_pt.begin();
11371  it_polyline != sorted_polyline_list_pt.end();
11372  it_polyline++)
11373  {
11374  tmp_sorted_polylines[counter] = *it_polyline;
11375  counter++;
11376  }
11377 
11378  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11379 
11380  ++curves_index;
11381 
11382  }while(n_sorted_polylines < n_unsorted_polylines);
11383 
11384 #ifdef PARANOID
11385  // Verify that the number of polylines on the sorted list is the same
11386  // as the number of polylines on the unsorted list
11387  if (n_sorted_polylines != n_unsorted_polylines)
11388  {
11389  std::stringstream err;
11390  err << "The number of polylines on the unsorted and sorted vectors"
11391  << " is different,\n"
11392  << "it means that not all the polylines have been sorted.\n"
11393  << "Sorted polylines: "<<n_sorted_polylines
11394  << "\nUnsorted polylines: "<<n_unsorted_polylines;
11395  throw OomphLibError(err.str(), "TriangleMesh::sort_polylines_helper()",
11396  OOMPH_EXCEPTION_LOCATION);
11397  }
11398 #endif
11399 
11400  }
11401 
11402  //======================================================================
11403  // \short Creates the shared boundaries
11404  //======================================================================
11405  template<class ELEMENT>
11407  OomphCommunicator* comm_pt,
11408  const Vector<unsigned> &element_domain,
11409  const Vector<GeneralisedElement*> &backed_up_el_pt,
11410  const Vector<FiniteElement*> &backed_up_f_el_pt,
11411  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11412  const bool& overrule_keep_as_halo_element_status)
11413  {
11414  // Storage for number of processors and current processor
11415  const unsigned nproc = comm_pt->nproc();
11416  const unsigned my_rank = comm_pt->my_rank();
11417 
11418  // Storage for all the halo elements on all processors
11419  // halo_element[iproc][jproc][ele_number]
11420  // Stores the "ele_number"-th halo element of processor "iproc" with
11421  // processor "jproc"
11422  Vector<Vector<Vector<GeneralisedElement*> > > halo_element_pt(nproc);
11423  // Create complete storage for the halo_element_pt container
11424  for (unsigned iproc = 0; iproc < nproc; iproc++)
11425  {halo_element_pt[iproc].resize(nproc);}
11426 
11427  // Store the global index of the element, used to check for possible
11428  // misclassification of halo elements in the above container
11429  // (halo_element_pt)
11430  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11431 
11432  // Get the halo elements on all processors
11433  this->get_halo_elements_on_all_procs(nproc, element_domain,
11434  backed_up_el_pt,
11435  processors_associated_with_data,
11436  overrule_keep_as_halo_element_status,
11437  element_to_global_index,
11438  halo_element_pt);
11439 
11440  // Resize the shared polylines container
11441  flush_shared_boundary_polyline_pt();
11442  Shared_boundary_polyline_pt.resize(nproc);
11443 
11444  // Create a set that store only the elements that will be kept in
11445  // the processor as nonhalo element, those whose element_domains is
11446  // equal to my_rank. This set is used when creating the shared
11447  // polylines and identify the connections to the original boundaries
11448  std::set<FiniteElement*> element_in_processor_pt;
11449  const unsigned n_ele = backed_up_f_el_pt.size();
11450  for (unsigned e = 0; e < n_ele; e++)
11451  {
11452  if (element_domain[e] == my_rank)
11453  {
11454  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11455  } // if (element_domain[e] == my_rank)
11456  } // for (e < n_elex)
11457 
11458  // Look for elements edges that may lie on internal boundaries
11459  // If that is the case then relate the face with the boundary on
11460  // which it lies
11461  std::map<std::pair<Node*,Node*>, unsigned> elements_edges_on_boundary;
11462  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11463 
11464  // Now we have all the halo elements on all processors. Use the
11465  // edges shared by the halo elements to create the shared boundaries.
11466  this->create_polylines_from_halo_elements_helper(element_domain,
11467  element_to_global_index,
11468  element_in_processor_pt,
11469  halo_element_pt,
11470  elements_edges_on_boundary,
11471  Shared_boundary_polyline_pt);
11472 
11473  }
11474 
11475  //======================================================================
11476  /// \short Creates the halo elements on all processors
11477  /// Gets the halo elements on all processors, these elements are then used
11478  /// on the function that computes the shared boundaries among the processors
11479  //======================================================================
11480  template<class ELEMENT>
11482  const unsigned &nproc, const Vector<unsigned> &element_domain,
11483  const Vector<GeneralisedElement*> &backed_up_el_pt,
11484  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11485  const bool&overrule_keep_as_halo_element_status,
11486  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11487  Vector<Vector<Vector<GeneralisedElement*> > > &output_halo_elements_pt)
11488  {
11489  const unsigned n_ele = backed_up_el_pt.size();
11490 
11491  // Loop over all the processors
11492  for (unsigned iproc = 0; iproc < nproc; iproc++)
11493  {
11494  // Boolean to know which elements has been already added to the
11495  // halo scheme on "iproc" processor
11496  Vector<std::map<GeneralisedElement*, bool> > already_added(nproc);
11497 
11498  // Loop over all backed up elements
11499  for (unsigned e=0;e<n_ele;e++)
11500  {
11501  // Get element and its domain
11502  GeneralisedElement* el_pt=backed_up_el_pt[e];
11503  unsigned el_domain=element_domain[e];
11504 
11505  // If element is NOT located on "iproc" processor then check if it is
11506  // halo with "el_domain" processor
11507  if (el_domain!=iproc)
11508  {
11509  // If this current mesh has been told to keep all elements as halos,
11510  // OR the element itself knows that it must be kept then
11511  // keep it
11512  if ((this->Keep_all_elements_as_halos) ||
11513  (el_pt->must_be_kept_as_halo()))
11514  {
11515  if (!overrule_keep_as_halo_element_status)
11516  {
11517  // Add as halo element whose non-halo counterpart is
11518  // located on processor "el_domain"
11519  if (!already_added[el_domain][el_pt])
11520  {
11521  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11522  already_added[el_domain][el_pt] = true;
11523  element_to_global_index[el_pt] = e;
11524  }
11525  }
11526  }
11527  // Otherwise: Is one of the nodes associated with other processor?
11528  else
11529  {
11530  //Can only have nodes if this is a finite element
11531  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11532  if(finite_el_pt!=0)
11533  {
11534  unsigned n_node = finite_el_pt->nnode();
11535  for (unsigned n=0;n<n_node;n++)
11536  {
11537  Node* nod_pt=finite_el_pt->node_pt(n);
11538 
11539  // Keep element?
11540  std::set<unsigned>::iterator it =
11541  processors_associated_with_data[nod_pt].find(iproc);
11542  if (it!=processors_associated_with_data[nod_pt].end())
11543  {
11544  // Add as root halo element whose non-halo counterpart is
11545  // located on processor "el_domain"
11546  if (!already_added[el_domain][el_pt])
11547  {
11548  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11549  already_added[el_domain][el_pt] = true;
11550  element_to_global_index[el_pt] = e;
11551  }
11552  // Now break out of loop over nodes
11553  break;
11554  } // if (it!=processors_associated_with_data[nod_pt].end())
11555  } // for (n < n_node)
11556  } // if (finite_el_pt!=0)
11557  } // else (this->Keep_all_elements_as_halos)
11558  } // if (el_domain!=iproc)
11559  } // for (e < nele)
11560  } // for (iproc < nproc)
11561 
11562  }
11563 
11564  //====================================================================
11565  // \short Get the element edges (pair of nodes, edges) that lie
11566  // on a boundary (used to mark shared boundaries that lie on
11567  // internal boundaries)
11568  //====================================================================
11569  template <class ELEMENT>
11571  std::map<std::pair<Node*,Node*>, unsigned> &element_edges_on_boundary)
11572  {
11573  // The number of original boundaries
11574  const unsigned nbound = this->nboundary();
11575  // Loop over the boundaries
11576  for (unsigned b = 0; b < nbound; b++)
11577  {
11578  // Keep track of the pair of nodes done
11579  std::map<std::pair<Node*, Node*>, bool> edge_done;
11580  // Get the number of elements on the boundary
11581  const unsigned nbound_ele = this->nboundary_element(b);
11582  for (unsigned e = 0; e < nbound_ele; e++)
11583  {
11584  // Get the boundary bulk element
11585  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11586  // Get the face index
11587  int face_index = this->face_index_at_boundary(b, e);
11588  // Create the face element
11589  FiniteElement* face_ele_pt =
11590  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
11591  // Get the number of nodes on the face element
11592  const unsigned nnodes = face_ele_pt->nnode();
11593  // Get the first and last node
11594  Node* first_node_pt = face_ele_pt->node_pt(0);
11595  Node* last_node_pt = face_ele_pt->node_pt(nnodes-1);
11596 
11597  // Create the pair to store the nodes
11598  std::pair<Node*,Node*> edge =
11599  std::make_pair(first_node_pt, last_node_pt);
11600 
11601  // Has the edge been included
11602  if (!edge_done[edge])
11603  {
11604  // Mark the edge as done
11605  edge_done[edge] = true;
11606 
11607  // Create the reversed version and mark it as done too
11608  std::pair<Node*,Node*> inv_edge =
11609  std::make_pair(last_node_pt, first_node_pt);
11610 
11611  // Mark the reversed edge as done
11612  edge_done[inv_edge] = true;
11613 
11614  // Mark the edge to belong to boundary b
11615  element_edges_on_boundary[edge] = b;
11616  } // if (!edge_done[edge])
11617 
11618  // Free the memory allocated for the face element
11619  delete face_ele_pt;
11620  face_ele_pt = 0;
11621 
11622  } // for (e < nbound_ele)
11623 
11624  } // for (b < nbound)
11625 
11626  }
11627 
11628  // ======================================================================
11629  // \short Creates polylines from the intersection of halo elements on
11630  // all processors. The new polylines define the shared boundaries in
11631  // the domain This method computes the polylines on ALL processors,
11632  // that is why the three dimensions in the structure
11633  // output_polylines_pt[iproc][ncurve][npolyline]
11634  // ======================================================================
11635  template<class ELEMENT>
11637  const Vector<unsigned> &element_domain,
11638  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11639  std::set<FiniteElement*> &element_in_processor_pt,
11640  Vector<Vector<Vector<GeneralisedElement*> > > &input_halo_elements,
11641  std::map<std::pair<Node*,Node*>, unsigned> &elements_edges_on_boundary,
11642  Vector<Vector<Vector<TriangleMeshPolyLine *> > > &output_polylines_pt)
11643  {
11644  const unsigned nproc = this->communicator_pt()->nproc();
11645  const unsigned my_rank = this->communicator_pt()->my_rank();
11646 
11647  // ---------------------------------------------------------------
11648  // Get the edges shared between each pair of processors
11649  // ---------------------------------------------------------------
11650 
11651  // Storage for the edges (pair of nodes) shared between a pair of
11652  // processors
11653  Vector<Vector<Vector<std::pair<Node*,Node*> > > > edges(nproc);
11654 
11655  // Each edge is associated to two elements, a haloi (halo element
11656  // in processors i) and a haloj (halo element in processors j)
11657  Vector<Vector<Vector<Vector<FiniteElement*> > > > edge_element_pt(nproc);
11658 
11659  // Each edge is associated to two elements, a haloi and a haloj,
11660  // the edge was created from a given face from each element, the
11661  // haloi face is stored at [0], the haloj face is stored at [1]
11662  Vector<Vector<Vector<Vector<int> > > > edge_element_face(nproc);
11663 
11664  // Store the possible internal boundary id associated to each edge
11665  // (-1 if there is no association). Some edges may overlap an
11666  // internal boundary (and only internal boundaries)
11667  Vector<Vector<Vector<int> > > edge_boundary(nproc);
11668 
11669  // Mark those edges (pair of nodes overlapped by a shared boundary)
11670  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
11671 
11672  // Resize the containers, they store info. for each pair of
11673  // processors
11674 
11675  // First resize the global container
11676  Shared_boundaries_ids.resize(nproc);
11677  for (unsigned j = 0 ; j < nproc; j++)
11678  {
11679  edges[j].resize(nproc);
11680  edge_element_pt[j].resize(nproc);
11681  edge_element_face[j].resize(nproc);
11682  edge_boundary[j].resize(nproc);
11683 
11684  // Resize the global container for shared boundaries ids
11685  Shared_boundaries_ids[j].resize(nproc);
11686 
11687  } // for (j < nproc)
11688 
11689  // Take the halo elements of processor "iproc" and compare their
11690  // edges with halo elements of other processors (except itself)
11691  for (unsigned iproc = 0; iproc < nproc; iproc++)
11692  {
11693  // Take the halo elements of processor iproc and compare with
11694  // other processors
11695  // Start from the iproc + 1,
11696  // 1) To avoid comparing with itself,
11697  // 2) To avoid generation of repeated boundaries
11698  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11699  {
11700  // **************************************************************
11701  // FIRST PART
11702  // 1) Get the halo elements of processor "iproc" with processor
11703  // "jproc"
11704  // 2) Get the halo elements of processor "jproc" with processor
11705  // "iproc"
11706  // 3) Compare their edges and those that match are the ones that
11707  // define the shared boundaries
11708  // **************************************************************
11709 
11710  // Storage for halo elements
11711  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11712  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11713 
11714  // Get the halo elements of "iproc" with "jproc"
11715  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11716 
11717  // If there are halo elements then there are shared boundaries
11718  const unsigned nhalo_elements_iproc_with_jproc =
11719  halo_elements_iproc_with_jproc.size();
11720 // DEBP(nhalo_elements_iproc_with_jproc);
11721  if (nhalo_elements_iproc_with_jproc > 0)
11722  {
11723  // Get the halo elements of "jproc" with "iproc"
11724  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11725 
11726  // If there are halo elements then there are shared
11727  // boundaries
11728  const unsigned nhalo_elements_jproc_with_iproc =
11729  halo_elements_jproc_with_iproc.size();
11730 // DEBP(nhalo_elements_jproc_with_iproc);
11731 #ifdef PARANOID
11732  if (nhalo_elements_jproc_with_iproc == 0)
11733  {
11734  // If there are halo elements of iproc with jproc there
11735  // MUST be halo elements on the other way round, not
11736  // necessary the same but at least one
11737  std::stringstream err;
11738  err <<"There are no halo elements from processor ("<<jproc<<") "
11739  <<"with processor ("<<iproc<<").\n"
11740  <<"This is strange since there are halo elements from "
11741  <<"processor ("<<iproc<<") with processor ("<<jproc<<").\n"
11742  <<"Number of halo elements from ("<<iproc<<") to ("
11743  <<jproc<<") : ("<< nhalo_elements_iproc_with_jproc<<")\n"
11744  <<"Number of halo elements from ("<<jproc<<") to ("
11745  <<iproc<<") : ("<< nhalo_elements_jproc_with_iproc<<")\n";
11746  throw OomphLibError(err.str(),
11747  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11748  OOMPH_EXCEPTION_LOCATION);
11749  }
11750 #endif
11751  // The edges are defined as pair of nodes
11752  Vector<Node*> halo_edges_iproc;
11753  unsigned halo_edges_counter_iproc = 0;
11754  Vector<Node*> halo_edges_jproc;
11755  unsigned halo_edges_counter_jproc = 0;
11756 
11757  // Map to associate the edge with the element used to create it
11758  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesi_to_element_pt;
11759 
11760  // Map to associated the edge with the face number of the
11761  // element that created it
11762  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11763  edgesi_element_pt_to_face_index;
11764 
11765  // Map to associate the edge with the element used to create it
11766  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesj_to_element_pt;
11767 
11768  // Map to associated the edge with the face number of the
11769  // element that created it
11770  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11771  edgesj_element_pt_to_face_index;
11772 
11773  // **************************************************************
11774  // 1.1) Store the edges of the "iproc" halo elements
11775  // **************************************************************
11776  // Go throught halo elements on "iproc" processor
11777  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11778  {
11779 #ifdef PARANOID
11780  unsigned e =
11781  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11782  // Only work with halo elements inside the "jproc" processor
11783  if (element_domain[e] != jproc)
11784  {
11785  // There was a problem on the ihalo-jhalo classification
11786  std::stringstream err;
11787  err << "There was a problem on the ihalo-jhalo classification.\n"
11788  << "One of the elements, (the one with the ("<<e<<")-th "
11789  << "index ) is not on the ("<<jproc<<")-th processor\n"
11790  << "but it was stored as a halo element of processor ("
11791  << iproc<<") with processor ("<<jproc<<").\n";
11792  throw OomphLibError(
11793  err.str(),
11794  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11795  OOMPH_EXCEPTION_LOCATION);
11796  }
11797 #endif
11798 
11799  FiniteElement* el_pt =
11800  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11801 
11802  if (el_pt==0)
11803  {
11804  std::stringstream err;
11805  err << "The halo element ("<<ih<<") could not be casted to the "
11806  << "FiniteElement type.\n";
11807  throw OomphLibError(
11808  err.str(),
11809  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11810  OOMPH_EXCEPTION_LOCATION);
11811  }
11812 
11813 #ifdef PARANOID
11814  // Number of nodes on this element
11815  const unsigned n_nodes = el_pt->nnode();
11816 
11817  // The number of nodes on every element should be at least
11818  // three since we are going to work with the cornes nodes,
11819  // the ones with index 0, 1 and 2
11820  if (n_nodes<3)
11821  {
11822  std::stringstream err;
11823  err << "The number of nodes of the "<<ih<<"-th halo element is"
11824  << " ("<< n_nodes << ").\nWe can not work with triangle "
11825  << "elements with less than three nodes\n";
11826  throw OomphLibError(err.str(),
11827  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11828  OOMPH_EXCEPTION_LOCATION);
11829  }
11830 #endif
11831 
11832  // Get the corner nodes, the first three nodes
11833  Node *first_node_pt = el_pt->node_pt(0);
11834  Node *second_node_pt = el_pt->node_pt(1);
11835  Node *third_node_pt = el_pt->node_pt(2);
11836 
11837  // Store the edges
11838  halo_edges_iproc.push_back(first_node_pt);
11839  halo_edges_iproc.push_back(second_node_pt);
11840  halo_edges_counter_jproc++;
11841 
11842  halo_edges_iproc.push_back(second_node_pt);
11843  halo_edges_iproc.push_back(third_node_pt);
11844  halo_edges_counter_jproc++;
11845 
11846  halo_edges_iproc.push_back(third_node_pt);
11847  halo_edges_iproc.push_back(first_node_pt);
11848  halo_edges_counter_jproc++;
11849 
11850  // Store the info. of the element used to create these edges
11851  std::pair<Node*, Node*> edge1 =
11852  std::make_pair(first_node_pt, second_node_pt);
11853  edgesi_to_element_pt[edge1] = el_pt;
11854 
11855  std::pair<Node*, Node*> edge2 =
11856  std::make_pair(second_node_pt, third_node_pt);
11857  edgesi_to_element_pt[edge2] = el_pt;
11858 
11859  std::pair<Node*, Node*> edge3 =
11860  std::make_pair(third_node_pt, first_node_pt);
11861  edgesi_to_element_pt[edge3] = el_pt;
11862 
11863  // Store the face index of the edge in the element
11864  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11865  std::make_pair(edge1, el_pt);
11866  edgesi_element_pt_to_face_index[edge_ele1] = 2;
11867 
11868  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11869  std::make_pair(edge2, el_pt);
11870  edgesi_element_pt_to_face_index[edge_ele2] = 0;
11871 
11872  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11873  std::make_pair(edge3, el_pt);
11874  edgesi_element_pt_to_face_index[edge_ele3] = 1;
11875 
11876  } // for (ih < nhalo_elements_iproc_with_jproc)
11877 
11878  // **************************************************************
11879  // 1.2) Store the edges of the "jproc" halo elements
11880  // **************************************************************
11881  // Go throught halo elements on "jproc" processor
11882  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
11883  {
11884 #ifdef PARANOID
11885  unsigned e =
11886  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
11887  // Only work with halo elements inside the "jproc" processor
11888  if (element_domain[e] != iproc)
11889  {
11890  // There was a problem on the jhalo-ihalo classification
11891  std::stringstream err;
11892  err << "There was a problem on the jhalo-ihalo classification.\n"
11893  << "One of the elements, (the one with the ("<<e<<")-th "
11894  << "index ) is not on the ("<<iproc<<")-th processor\n"
11895  << "but it was stored as a halo element of processor ("
11896  << jproc<<") with processor ("<<iproc<<").\n";
11897  throw OomphLibError(
11898  err.str(),
11899  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11900  OOMPH_EXCEPTION_LOCATION);
11901  }
11902 #endif
11903 
11904  FiniteElement* el_pt =
11905  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
11906  if (el_pt==0)
11907  {
11908  std::stringstream err;
11909  err << "The halo element ("<<jh<<") could not be casted to the "
11910  << "FiniteElement type.\n";
11911  throw OomphLibError(
11912  err.str(),
11913  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11914  OOMPH_EXCEPTION_LOCATION);
11915  }
11916 
11917 #ifdef PARANOID
11918  // Number of nodes on this element
11919  const unsigned n_nodes = el_pt->nnode();
11920 
11921  // The number of nodes on every element should be at least
11922  // three since we are going to work with the cornes nodes,
11923  // the ones with index 0, 1 and 2
11924  if (n_nodes<3)
11925  {
11926  std::stringstream err;
11927  err << "The number of nodes of the "<<jh<<"-th halo element is"
11928  << " ("<< n_nodes << ").\nWe can not work with triangle "
11929  << "elements with less than three nodes\n";
11930  throw OomphLibError(err.str(),
11931  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11932  OOMPH_EXCEPTION_LOCATION);
11933  }
11934 #endif
11935 
11936  // Get the nodes pointers
11937  Node *first_node_pt = el_pt->node_pt(0);
11938  Node *second_node_pt = el_pt->node_pt(1);
11939  Node *third_node_pt = el_pt->node_pt(2);
11940 
11941  // Store the edges
11942  halo_edges_jproc.push_back(first_node_pt);
11943  halo_edges_jproc.push_back(second_node_pt);
11944  halo_edges_counter_iproc++;
11945 
11946  halo_edges_jproc.push_back(second_node_pt);
11947  halo_edges_jproc.push_back(third_node_pt);
11948  halo_edges_counter_iproc++;
11949 
11950  halo_edges_jproc.push_back(third_node_pt);
11951  halo_edges_jproc.push_back(first_node_pt);
11952  halo_edges_counter_iproc++;
11953 
11954  // Store the info. of the element used to create these edges
11955  std::pair<Node*, Node*> edge1 =
11956  std::make_pair(first_node_pt, second_node_pt);
11957  edgesj_to_element_pt[edge1] = el_pt;
11958 
11959  std::pair<Node*, Node*> edge2 =
11960  std::make_pair(second_node_pt, third_node_pt);
11961  edgesj_to_element_pt[edge2] = el_pt;
11962 
11963  std::pair<Node*, Node*> edge3 =
11964  std::make_pair(third_node_pt, first_node_pt);
11965  edgesj_to_element_pt[edge3] = el_pt;
11966 
11967  // Store the face index of the edge in the element
11968  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11969  std::make_pair(edge1, el_pt);
11970  edgesj_element_pt_to_face_index[edge_ele1] = 2;
11971 
11972  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11973  std::make_pair(edge2, el_pt);
11974  edgesj_element_pt_to_face_index[edge_ele2] = 0;
11975 
11976  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11977  std::make_pair(edge3, el_pt);
11978  edgesj_element_pt_to_face_index[edge_ele3] = 1;
11979 
11980  } // for (jh < nhalo_elements_jproc_with_iproc)
11981 
11982  // ***************************************************************
11983  // SECOND PART
11984  // 1) We already have the information of the edges on the iproc
11985  // halo and jproc halo elements
11986  // 2) Identify the shared edges to create the shared boundaries
11987  // (Only store the information but do not create the polyline)
11988  // ***************************************************************
11989 
11990  // Get the number of edges from each processor
11991  unsigned nhalo_iedges = halo_edges_iproc.size();
11992  unsigned nhalo_jedges = halo_edges_jproc.size();
11993 
11994  // Start comparing the edges to check which of those are
11995  // shared between the "ihalo_edge" and the "jhalo_edge"
11996  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe+=2)
11997  {
11998  // Get the ihe-th edge (pair of nodes)
11999  Vector<Node*> ihalo_edge(2);
12000  ihalo_edge[0] = halo_edges_iproc[ihe];
12001  ihalo_edge[1] = halo_edges_iproc[ihe+1];
12002 
12003  // Create the pair that defines the edge
12004  std::pair<Node*,Node*> tmp_edge = std::make_pair(ihalo_edge[0],
12005  ihalo_edge[1]);
12006 
12007  // Check if the edge lies on a boundary (default values is
12008  // -1 for no association with an internal boundary)
12009  int edge_boundary_id = -1;
12010  {
12011  std::map<std::pair<Node*,Node*>,unsigned >::iterator it;
12012  it = elements_edges_on_boundary.find(tmp_edge);
12013  // If the edges lie on a boundary then get the boundary id
12014  // on which the edges lie
12015  if (it != elements_edges_on_boundary.end())
12016  {
12017  // Assign the internal boundary id associated with the
12018  // edge
12019  edge_boundary_id = (*it).second;
12020  }
12021  else
12022  {
12023  // Look for the reversed version of the edge (the nodes
12024  // inverted)
12025  std::pair<Node*,Node*> rtmp_edge = std::make_pair(ihalo_edge[1],
12026  ihalo_edge[0]);
12027  it = elements_edges_on_boundary.find(rtmp_edge);
12028  if (it != elements_edges_on_boundary.end())
12029  {
12030  // Assign the internal boundary id associated with the
12031  // edge
12032  edge_boundary_id = (*it).second;
12033  }
12034  }
12035  }
12036 
12037  // Go through the jhalo_edge and compare with the
12038  // ihalo_edge
12039  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe+=2)
12040  {
12041  // Get the jhe-th edge (pair of nodes)
12042  Vector<Node*> jhalo_edge(2);
12043  jhalo_edge[0] = halo_edges_jproc[jhe];
12044  jhalo_edge[1] = halo_edges_jproc[jhe+1];
12045 
12046  // Comparing pointer of nodes
12047  if (ihalo_edge[0] == jhalo_edge[0] &&
12048  ihalo_edge[1] == jhalo_edge[1])
12049  {
12050  // Create the edge (both nodes that make the edge)
12051  std::pair<Node*, Node*> new_edge =
12052  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12053 
12054  // Get the elements involved in the creation of the
12055  // edge to check that there are elements associated to
12056  // the edge
12057  FiniteElement* haloi_ele_pt = 0;
12058  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12059  FiniteElement* haloj_ele_pt = 0;
12060  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12061 
12062  // Verify that there is an element associated with it
12063  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12064  {
12065  std::stringstream err;
12066  err << "There is no associated elements with the new "
12067  << "shared boundary. This is an storing problem,\n"
12068  << "possibly related with a memory leak problem!!!\n"
12069  << "The nodes that compound the edge are these:\n"
12070  << "On processor ("<<iproc<<"):\n"
12071  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12072  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12073  <<ihalo_edge[1]->x(1)<<")\n\n"
12074  << "On processor ("<<jproc<<"):\n"
12075  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12076  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12077  <<jhalo_edge[1]->x(1)<<")\n\n"
12078  << "The nodes coordinates should be the same!!!\n";
12079  throw OomphLibError(err.str(),
12080  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12081  OOMPH_EXCEPTION_LOCATION);
12082  }
12083 
12084  // Store the edge
12085  edges[iproc][jproc].push_back(new_edge);
12086 
12087  // Is the edge overlapped by a shared boundary
12088  if (edge_boundary_id >= 0)
12089  {
12090  // Mark the edge as overlapped
12091  overlapped_edge[new_edge] = true;
12092 
12093  // Also mark the reversed edge
12094  std::pair<Node*, Node*> rev_new_edge =
12095  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12096 
12097  // Mark the edge as overlapped
12098  overlapped_edge[rev_new_edge] = true;
12099 
12100  } // if (edge_boundary_id >= 0)
12101 
12102  // Store the internal boundary id (default -1)
12103  // associated to the edge
12104  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12105 
12106  // Store the two elements associated with the edge
12107  Vector<FiniteElement*> tmp_elements_pt;
12108  tmp_elements_pt.push_back(haloi_ele_pt);
12109  tmp_elements_pt.push_back(haloj_ele_pt);
12110 
12111  // Associate the edge with the elements that gave rise to it
12112  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12113 
12114  // Get the face index on each element that gave rise to
12115  // the edge
12116 
12117  // .. first create the pair (edge, finite_element)
12118  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12119  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12120 
12121  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12122  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12123 
12124  // Set default values to later check if values were
12125  // read from the map structure
12126  int face_index_haloi_ele = -1;
12127  face_index_haloi_ele =
12128  edgesi_element_pt_to_face_index[edge_elementi_pair];
12129  int face_index_haloj_ele = -1;
12130  face_index_haloj_ele =
12131  edgesj_element_pt_to_face_index[edge_elementj_pair];
12132  // Verify that there is an element associated with it
12133  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12134  {
12135  std::stringstream err;
12136  err << "There is no associated face indexes to the"
12137  << "elements that gave\nrise to the shared edge\n"
12138  << "The nodes that compound the edge are these:\n"
12139  << "On processor ("<<iproc<<"):\n"
12140  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12141  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12142  <<ihalo_edge[1]->x(1)<<")\n\n"
12143  << "On processor ("<<jproc<<"):\n"
12144  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12145  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12146  <<jhalo_edge[1]->x(1)<<")\n\n"
12147  << "The nodes coordinates should be the same!!!\n";
12148  throw OomphLibError(err.str(),
12149  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12150  OOMPH_EXCEPTION_LOCATION);
12151  } // if (face_index_haloi_ele == -1 ||
12152  // face_index_haloj_ele == -1)
12153 
12154  // Get the face indexes from the map structure
12155  Vector<int> tmp_edge_element_face_index;
12156  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12157  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12158  // Store the face indexes
12159  edge_element_face[iproc][jproc].
12160  push_back(tmp_edge_element_face_index);
12161 
12162  break; // break for (jhe < nhalo_jedges) since edge
12163  // found
12164 
12165  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12166  // ihalo_edge[1] == jhalo_edge[1])
12167  // Comparing nodes pointers
12168  else if (ihalo_edge[0] == jhalo_edge[1] &&
12169  ihalo_edge[1] == jhalo_edge[0])
12170  {
12171  // Create the edge (both nodes that make the edge)
12172  std::pair<Node*, Node*> new_edge =
12173  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12174 
12175  // Get the elements involved in the creation of the
12176  // edge
12177  FiniteElement* haloi_ele_pt = 0;
12178  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12179 
12180  FiniteElement* haloj_ele_pt = 0;
12181  // Create the edge (reversed, that is how it was
12182  // originally stored)
12183  std::pair<Node*, Node*> new_edge_reversed =
12184  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12185  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12186 
12187  // Verify that there is an element associated with it
12188  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12189  {
12190  std::stringstream err;
12191  err << "There is no associated elements with the new "
12192  << "shared boundary (reversed version). This is an "
12193  << "storing problem, possibly related with a memory "
12194  << "leak problem!!!\n"
12195  << "The nodes that compound the edge are these:\n"
12196  << "On processor ("<<iproc<<"):\n"
12197  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12198  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12199  <<ihalo_edge[1]->x(1)<<")\n\n"
12200  << "On processor ("<<jproc<<"):\n"
12201  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12202  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12203  <<jhalo_edge[1]->x(1)<<")\n\n"
12204  << "The nodes coordinates should be the same!!!\n";
12205  throw OomphLibError(err.str(),
12206  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12207  OOMPH_EXCEPTION_LOCATION);
12208  }
12209 
12210  // Store the edge
12211  edges[iproc][jproc].push_back(new_edge);
12212 
12213  // Is the edge overlapped by a shared boundary
12214  if (edge_boundary_id >= 0)
12215  {
12216  // Mark the edge as overlapped
12217  overlapped_edge[new_edge] = true;
12218 
12219  // Also mark the reversed edge
12220  std::pair<Node*, Node*> rev_new_edge =
12221  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12222 
12223  // Mark the edge as overlapped
12224  overlapped_edge[rev_new_edge] = true;
12225  } // if (edge_boundary_id >= 0)
12226 
12227  // Store the internal boundary id (default -1)
12228  // associated to the edge
12229  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12230 
12231  // Store the two elements associated with the edge
12232  Vector<FiniteElement*> tmp_elements_pt;
12233  tmp_elements_pt.push_back(haloi_ele_pt);
12234  tmp_elements_pt.push_back(haloj_ele_pt);
12235 
12236  // Associate the edge with the elements that gave rise to it
12237  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12238 
12239  // Get the face index on each element that gave rise to
12240  // the edge
12241 
12242  // .. first create the pair (edge, finite_element)
12243  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12244  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12245 
12246  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12247  edge_elementj_pair = make_pair(new_edge_reversed,
12248  haloj_ele_pt);
12249 
12250  // Set default values to later check if values were
12251  // read from the map structure
12252  int face_index_haloi_ele = -1;
12253  face_index_haloi_ele =
12254  edgesi_element_pt_to_face_index[edge_elementi_pair];
12255  int face_index_haloj_ele = -1;
12256  face_index_haloj_ele =
12257  edgesj_element_pt_to_face_index[edge_elementj_pair];
12258  // Verify that there is an element associated with it
12259  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12260  {
12261  std::stringstream err;
12262  err << "There is no associated face indexes to the"
12263  << "elements that gave\nrise to the shared edge\n"
12264  << "The nodes that compound the edge are these:\n"
12265  << "On processor ("<<iproc<<"):\n"
12266  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12267  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12268  <<ihalo_edge[1]->x(1)<<")\n\n"
12269  << "On processor ("<<jproc<<"):\n"
12270  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12271  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12272  <<jhalo_edge[1]->x(1)<<")\n\n"
12273  << "The nodes coordinates should be the same!!!\n";
12274  throw OomphLibError(err.str(),
12275  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12276  OOMPH_EXCEPTION_LOCATION);
12277  } // if (face_index_haloi_ele == -1 ||
12278  // face_index_haloj_ele == -1)
12279 
12280  // Get the face indexes from the map structure
12281  Vector<int> tmp_edge_element_face_index;
12282  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12283  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12284  // Store the face indexes
12285  edge_element_face[iproc][jproc].
12286  push_back(tmp_edge_element_face_index);
12287 
12288  break; // break for (jhe < nhalo_jedges) since edge found
12289 
12290  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12291  // ihalo_edge[1] == jhalo_edge[0])
12292 
12293  } // for (jhe < nhaloj_edges)
12294 
12295  } // for (ihe < nhaloi_edges)
12296 
12297  } // if (nhalo_elements_iproc_with_jproc > 0)
12298 
12299  } // for (jproc < nproc)
12300 
12301  } // for (iproc < nproc)
12302 
12303  // ------------------------------------------------------------------
12304  // Compute the degree of each node in the shared edges
12305  // ------------------------------------------------------------------
12306 
12307  // Visit all the shared edges between each pair of processors,
12308  // visit the nodes of each edge and compute the degree of each node
12309 
12310  // Store the degree (valency) of each node
12311  std::map<Node*, unsigned> global_shared_node_degree;
12312 
12313 #ifdef PARANOID
12314  // Map to check if an edge has been already visited
12315  std::map<std::pair<Node*, Node*>,bool> edge_done;
12316 #endif // #ifdef PARANOID
12317  // Map to check if a node has been already visited
12318  std::map<Node*,bool> node_done;
12319 
12320  // Loop over the processors and get the shared edged between each
12321  // pair of processors
12322  for (unsigned iproc = 0; iproc < nproc; iproc++)
12323  {
12324  // Start from iproc + 1 to avoid checking with itself (there is
12325  // no shared edges between the same processor), and to avoid
12326  // double counting the edges and nodes (the shared edges between
12327  // processor (iproc, jproc) are the same as those between
12328  // processor jproc, iproc)
12329  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12330  {
12331  // Get the number of edges shared between the pair of processors
12332  const unsigned nshd_edges = edges[iproc][jproc].size();
12333 #ifdef PARANOID
12334  // There must be the same number of information on each of the
12335  // containers
12336 
12337  // Get the number of edge elements
12338  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12339  if (nshd_edges != nedge_element)
12340  {
12341  std::stringstream error_message;
12342  error_message
12343  << "The number of shared edges between processor iproc and jproc\n"
12344  << "is different form the number of edge elements between the\n"
12345  << "pair of processors\n"
12346  << "iproc: (" << iproc << ")\n"
12347  << "jproc: (" << jproc << ")\n"
12348  << "# of shared edges: (" << nshd_edges << ")\n"
12349  << "# of edge elements: (" << nedge_element << ")\n\n";
12350  throw OomphLibError(error_message.str(),
12351  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12352  OOMPH_EXCEPTION_LOCATION);
12353  }
12354 
12355  // Get the number of edge element faces
12356  const unsigned nedge_element_face =
12357  edge_element_face[iproc][jproc].size();
12358  if (nshd_edges != nedge_element_face)
12359  {
12360  std::stringstream error_message;
12361  error_message
12362  << "The number of shared edges between processor iproc and jproc\n"
12363  << "is different form the number of edge element faces between the\n"
12364  << "pair of processors\n"
12365  << "iproc: (" << iproc << ")\n"
12366  << "jproc: (" << jproc << ")\n"
12367  << "# of shared edges: (" << nshd_edges << ")\n"
12368  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12369  throw OomphLibError(error_message.str(),
12370  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12371  OOMPH_EXCEPTION_LOCATION);
12372  }
12373 
12374  // Get the number of edge boundaries
12375  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12376  if (nshd_edges != nedge_boundary)
12377  {
12378  std::stringstream error_message;
12379  error_message
12380  << "The number of shared edges between processor iproc and jproc\n"
12381  << "is different form the number of edge boundaries ids between the\n"
12382  << "pair of processors\n"
12383  << "iproc: (" << iproc << ")\n"
12384  << "jproc: (" << jproc << ")\n"
12385  << "# of shared edges: (" << nshd_edges << ")\n"
12386  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12387  throw OomphLibError(error_message.str(),
12388  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12389  OOMPH_EXCEPTION_LOCATION);
12390  }
12391 
12392 #endif // #ifdef PARANOID
12393 
12394  // Loop over the shared edges between (iproc, jproc) processors
12395  for (unsigned se = 0; se < nshd_edges; se++)
12396  {
12397  // Get the edge
12398  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12399 #ifdef PARANOID
12400  // Check that the edge has not been previously visited
12401  if (edge_done[edge])
12402  {
12403  std::stringstream error_message;
12404  error_message
12405  << "The shared edge between processor iproc and processor\n"
12406  << "jproc has been already visited, this is weird since the\n"
12407  << "edge should not be shared by other pair of processors\n"
12408  << "iproc: (" << iproc << ")\n"
12409  << "jproc: (" << jproc << ")\n"
12410  << "First node of edge: (" << edge.first->x(0) << ", "
12411  << edge.first->x(1) << ")\n"
12412  << "Second node of edge: (" << edge.second->x(0) << ", "
12413  << edge.second->x(1) << ")\n"
12414  << "Associated edge boundary id: ("
12415  << edge_boundary[iproc][jproc][se] << ")\n\n";
12416  throw OomphLibError(error_message.str(),
12417  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12418  OOMPH_EXCEPTION_LOCATION);
12419  }
12420 
12421  // Mark the edge as done
12422  edge_done[edge] = true;
12423  // Create the reversed version and include it too
12424  std::pair<Node*, Node*> rev_edge =
12425  std::make_pair(edge.second, edge.first);
12426  // Mark reversed edge as done
12427  edge_done[rev_edge] = true;
12428 #endif // #ifdef PARANOID
12429 
12430  // Get each of the nodes that conform the edge
12431  Node* left_node_pt = edge.first;
12432  Node* right_node_pt = edge.second;
12433 
12434  // Check if the left node has been already done
12435  if (!node_done[left_node_pt])
12436  {
12437  // Set the degree of the node to once since this is the
12438  // first time it has been found
12439  global_shared_node_degree[left_node_pt] = 1;
12440 
12441  } // if (!done_node[left_node_pt])
12442  else
12443  {
12444  // Increase the degree of the node
12445  global_shared_node_degree[left_node_pt]++;
12446  }
12447 
12448  // Check if the right node has been already done
12449  if (!node_done[right_node_pt])
12450  {
12451  // Set the degree of the node to once since this is the
12452  // first time it has been found
12453  global_shared_node_degree[right_node_pt] = 1;
12454  } // if (!done_node[right_node_pt])
12455  else
12456  {
12457  // Increase the degree of the node
12458  global_shared_node_degree[right_node_pt]++;
12459  }
12460 
12461  } // for (se < nshd_edges)
12462 
12463  } // for (jproc < nproc)
12464 
12465  } // for (iproc < nproc)
12466 
12467  // -----------------------------------------------------------------
12468  // Identify those nodes living on edges of original boundaries not
12469  // overlapped by a shared boundary
12470 
12471  // Mark the nodes on original boundaries not overlapped by shared
12472  // boundaries
12473  std::map<unsigned, std::map<Node*, bool> >
12474  node_on_bnd_not_overlapped_by_shd_bnd;
12475 
12476  // Loop over the edges of the original boundaries
12477  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
12478  elements_edges_on_boundary.begin();
12479  it_map != elements_edges_on_boundary.end(); it_map++)
12480  {
12481  // Get the edge
12482  std::pair<Node*,Node*> edge_pair = (*it_map).first;
12483 
12484  // Is the edge overlaped by a shared boundary
12485  if (!overlapped_edge[edge_pair])
12486  {
12487  // Mark the nodes of the edge as being on an edge not overlaped
12488  // by a shared boundary on the boundary the edge is
12489  unsigned b = (*it_map).second;
12490 
12491  // Get the left node
12492  Node* left_node_pt = edge_pair.first;
12493  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12494 
12495  // Get the right node
12496  Node* right_node_pt = edge_pair.second;
12497  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12498 
12499  } // if (!overlapped_edge[edge_pair])
12500 
12501  } // Loop over edges to mark those nodes on overlaped edge by
12502  // shared boundaries
12503 
12504  // ------------------------------------------------------------------
12505  // Now create the shared polylines but including the degree of the
12506  // nodes as a nw stop condition for adding more edges to the side
12507  // or a root edge
12508  // ------------------------------------------------------------------
12509 
12510  // Storage for new created polylines with "each processor", non
12511  // sorted (shared polylines of the current processor only)
12512  Vector<Vector<TriangleMeshPolyLine *> > unsorted_polylines_pt(nproc);
12513 
12514  // Map that associates the shared boundary id with the list of
12515  // nodes that create it (shared boundary of the current processor
12516  // only)
12517  std::map<unsigned, std::list<Node*> > shared_bnd_id_to_sorted_list_node_pt;
12518 
12519  // Get maximum user boundary id and set the initial shared boundary
12520  // id
12521  unsigned shared_boundary_id_start = this->nboundary();
12522  Initial_shared_boundary_id = shared_boundary_id_start;
12523 
12524  // Aqui
12525 
12526  // Loop over the processors and get the shared edged between each
12527  // pair of processors
12528  for (unsigned iproc = 0; iproc < nproc; iproc++)
12529  {
12530  // Start from iproc + 1 to avoid checking with itself (there is
12531  // no shared edges between the same processor), and to avoid
12532  // double counting the edges and nodes (the shared edges between
12533  // processor (iproc, jproc) are the same as those between
12534  // processor jproc, iproc)
12535  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12536  {
12537  // *************************************************************
12538  // THIRD PART
12539  // 1) Sort the edges (make them contiguous) so that they can
12540  // be used as the vertex coordinates that define a shared
12541  // boundary (polyline)
12542  // *************************************************************
12543  unsigned npolylines_counter = 0;
12544  const unsigned nedges = edges[iproc][jproc].size();
12545 
12546  // -----------------------------------------------------------
12547  // Compute all the SHARED POLYLINES
12548  // -----------------------------------------------------------
12549  // The number of sorted edges
12550  unsigned nsorted_edges = 0;
12551 
12552  // Keep track of the already done edges
12553  std::map<std::pair<Node*,Node*>, bool> edge_done;
12554 
12555  // Loop over all the edges to create all the polylines with
12556  // the current processors involved
12557  while(nsorted_edges < nedges)
12558  {
12559  // Temporaly storage for the elements associated to the
12560  // sorted edges
12561  std::list<FiniteElement*> tmp_boundary_element_pt;
12562  // Temporly storage for the face indexes on the element
12563  // that created the given edge
12564  std::list<int> tmp_face_index_element;
12565  // Get an initial pair of nodes to create an edge
12566  std::pair<Node*,Node*> edge;
12567 #ifdef PARANOID
12568  bool found_initial_edge = false;
12569 #endif
12570  int root_edge_bound_id = -1;
12571  unsigned iedge = 0;
12572  for (iedge = 0; iedge < nedges; iedge++)
12573  {
12574  edge = edges[iproc][jproc][iedge];
12575  // If not done then take it as initial edge
12576  if (!edge_done[edge])
12577  {
12578  // Get the boundary id that the edge may be overlapping
12579  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12580 #ifdef PARANOID
12581  found_initial_edge = true;
12582 #endif
12583  nsorted_edges++;
12584  iedge++;
12585  break;
12586  } // if (!edge_done[edge])
12587  } // for (iedge < nedges)
12588 
12589 #ifdef PARANOID
12590  if (!found_initial_edge)
12591  {
12592  std::ostringstream error_message;
12593  error_message
12594  << "All the edge are already done, but the number of done\n"
12595  << "edges ("<<nsorted_edges<<") is still less than the total\n"
12596  << "number of edges (" << nedges << ").\n";
12597  // << "----- Possible memory leak -----\n";
12598  throw OomphLibError(error_message.str(),
12599  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12600  OOMPH_EXCEPTION_LOCATION);
12601  }
12602 #endif
12603 
12604  // Storing for the sorting nodes extracted from the
12605  // edges. The sorted nodes are used to create a polyline
12606  std::list<Node*> sorted_nodes;
12607  sorted_nodes.clear();
12608 
12609  // The initial and final nodes of the list
12610  Node *first_node_pt = edge.first;
12611  Node *last_node_pt = edge.second;
12612 
12613  // Push back on the list the new edge (nodes)
12614  sorted_nodes.push_back(first_node_pt);
12615  sorted_nodes.push_back(last_node_pt);
12616 
12617  // Get the elements associated to the edge and store them
12618  // in the temporaly boundary elements storage
12619  tmp_boundary_element_pt.
12620  push_back(edge_element_pt[iproc][jproc][iedge-1][0]);
12621  tmp_boundary_element_pt.
12622  push_back(edge_element_pt[iproc][jproc][iedge-1][1]);
12623 
12624  // ... then get the face index of the element from where
12625  // the edge came from
12626  tmp_face_index_element.
12627  push_back(edge_element_face[iproc][jproc][iedge-1][0]);
12628  tmp_face_index_element.
12629  push_back(edge_element_face[iproc][jproc][iedge-1][1]);
12630 
12631  // Mark edge as done
12632  edge_done[edge] = true;
12633 
12634  // Continue iterating if a new node (that creates a new
12635  // edge) is added to the list, we have just added two nodes
12636  // (the first and last of the root edge)
12637  bool node_added = true;
12638 
12639  // Flags to indicate at which end the node was added (left
12640  // or right)
12641  bool node_added_to_the_left = true;
12642  bool node_added_to_the_right = true;
12643 
12644  // The nodes that create a shared boundary are obtained by
12645  // connecting the edges shared by the halo and haloed
12646  // elements. These edges are connected to left or right of
12647  // the shared boundary. Every time a new edge is added to
12648  // the left (or right), the most left (or right) node is
12649  // searched in the list of nodes of previous shared
12650  // boundaries, if the node is found then it is said to be
12651  // shared with another boundary and a connection to that
12652  // boundary needs to be specified. We stop adding edges
12653  // (and nodes) to the side where that nodes was found to be
12654  // shared. Note that the intersection (shared node) may be
12655  // with the same shared boundary
12656 
12657  // Flag to indicate a node was found to be shared with
12658  // another boundary at the left end (most left node) of the
12659  // shared boundary
12660  bool connection_to_the_left = false;
12661 
12662  // Flag to indicate a node was found to be shared with
12663  // another boundary at the right end (most right node) of
12664  // the shared boundary
12665  bool connection_to_the_right = false;
12666 
12667  // Flag to stop the adding of edges (and nodes) to the
12668  // current shared boundary
12669  bool current_polyline_has_connections_at_both_ends = false;
12670 
12671  // Store the boundary ids of the polylines to connect (only
12672  // used when the polyline was found to have a connection)
12673  // -1: Indicates no connection
12674  // -2: Indicates connection with itself
12675  // Any other value: Boundary id to connect
12676  int bound_id_connection_to_the_left = -1;
12677  int bound_id_connection_to_the_right = -1;
12678 
12679  // Get the degree of the first node
12680  const unsigned first_node_degree =
12681  global_shared_node_degree[first_node_pt];
12682 
12683  // Check if the nodes of the root edge have connections
12684  // ... to the left
12685  bound_id_connection_to_the_left =
12686  check_connections_of_polyline_nodes(
12687  element_in_processor_pt,
12688  root_edge_bound_id,
12689  overlapped_edge,
12690  node_on_bnd_not_overlapped_by_shd_bnd,
12691  sorted_nodes,
12692  shared_bnd_id_to_sorted_list_node_pt,
12693  first_node_degree,
12694  first_node_pt);
12695 
12696  // If there is a connection then set the
12697  // corresponding flag
12698  // (-1): No connection
12699  // (-2): Connection with itself
12700  // (-3): No connection, stop adding nodes
12701  // (other value): Boundary id
12702  if (bound_id_connection_to_the_left != -1)
12703  {
12704  connection_to_the_left = true;
12705  } // if (bound_id_connection_to_the_left != -1)
12706 
12707  // Get the degree of the last node
12708  const unsigned last_node_degree =
12709  global_shared_node_degree[last_node_pt];
12710 
12711  // Check if the nodes of the root edge have connections
12712  // ... to the right
12713  bound_id_connection_to_the_right =
12714  check_connections_of_polyline_nodes(
12715  element_in_processor_pt,
12716  root_edge_bound_id,
12717  overlapped_edge,
12718  node_on_bnd_not_overlapped_by_shd_bnd,
12719  sorted_nodes,
12720  shared_bnd_id_to_sorted_list_node_pt,
12721  last_node_degree,
12722  last_node_pt);
12723 
12724  // If there is a connection then set the
12725  // corresponding flag
12726  // (-1): No connection
12727  // (-2): Connection with itself
12728  // (other value): Boundary id
12729  if (bound_id_connection_to_the_right != -1)
12730  {
12731  connection_to_the_right = true;
12732  } // if (bound_id_connection_to_the_right != -1)
12733 
12734  // If the current shared boundary has connections at both
12735  // ends then stop the adding of nodes
12736  if (connection_to_the_left && connection_to_the_right)
12737  {current_polyline_has_connections_at_both_ends = true;}
12738 
12739  // Continue searching for more edges if
12740  // 1) A new node was added at the left or right of the list
12741  // 2) There are more edges to possible add
12742  // 3) The added node is not part of any other previous
12743  // shared polyline
12744  while(node_added && (nsorted_edges < nedges)
12745  && !current_polyline_has_connections_at_both_ends)
12746  {
12747  // Start from the next edge since we have already added
12748  // the previous one as the initial edge (any previous
12749  // edge had to be added to previous polylines)
12750  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12751  {
12752  // Reset the flags for added nodes, to the left and right
12753  node_added = false;
12754  node_added_to_the_left = false;
12755  node_added_to_the_right = false;
12756  // Get the current edge
12757  edge = edges[iproc][jproc][iiedge];
12758  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12759 
12760  // We need to ensure to connect with edges that share
12761  // the same bound id or with those that has no boundary
12762  // id associated (the default -1 value), may apply
12763  // exclusively to internal boundaries
12764  if (!edge_done[edge] &&
12765  (edge_bound_id == root_edge_bound_id))
12766  {
12767  // Get each individual node
12768  Node* left_node_pt = edge.first;
12769  Node* right_node_pt = edge.second;
12770 
12771  // Pointer to the new added node
12772  Node* new_added_node_pt = 0;
12773 
12774  // Is the node to be added to the left?
12775  if (left_node_pt == first_node_pt &&
12776  !connection_to_the_left)
12777  {
12778  // Push front the new node
12779  sorted_nodes.push_front(right_node_pt);
12780  // Update the new added node and the first node
12781  new_added_node_pt = first_node_pt = right_node_pt;
12782  // Set the node added flag to true
12783  node_added = true;
12784  // Indicate the node was added to the left
12785  node_added_to_the_left = true;
12786  }
12787  // Is the node to be added to the right?
12788  else if (left_node_pt == last_node_pt &&
12789  !connection_to_the_right)
12790  {
12791  // Push back the new node
12792  sorted_nodes.push_back(right_node_pt);
12793  // Update the new added node and the last node
12794  new_added_node_pt = last_node_pt = right_node_pt;
12795  // Set the node added flag to true
12796  node_added = true;
12797  // Indicate the node was added to the right
12798  node_added_to_the_right = true;
12799  }
12800  // Is the node to be added to the left?
12801  else if (right_node_pt == first_node_pt &&
12802  !connection_to_the_left)
12803  {
12804  // Push front the new node
12805  sorted_nodes.push_front(left_node_pt);
12806  // Update the new added node and the first node
12807  new_added_node_pt = first_node_pt = left_node_pt;
12808  // Set the node added flag to true
12809  node_added = true;
12810  // Indicate the node was added to the left
12811  node_added_to_the_left = true;
12812  }
12813  // Is the node to be added to the right?
12814  else if (right_node_pt == last_node_pt &&
12815  !connection_to_the_right)
12816  {
12817  // Push back the new node
12818  sorted_nodes.push_back(left_node_pt);
12819  // Update the new added node and the last node
12820  new_added_node_pt = last_node_pt = left_node_pt;
12821  // Set the node added flag to true
12822  node_added = true;
12823  // Indicate the node was added to the right
12824  node_added_to_the_right = true;
12825  }
12826 
12827  // If we added a new node then we need to check if
12828  // that node has been already added in other shared
12829  // boundaries (which may define a connection)
12830  if (node_added)
12831  {
12832  // Mark as done only if one of its nodes has been
12833  // added to the list
12834  edge_done[edge] = true;
12835  nsorted_edges++;
12836 
12837  // Get the degree of the added node
12838  const unsigned added_node_degree =
12839  global_shared_node_degree[new_added_node_pt];
12840 
12841  if (node_added_to_the_left)
12842  {
12843  // Add the bulk elements
12844  tmp_boundary_element_pt.push_front(
12845  edge_element_pt[iproc][jproc][iiedge][1]);
12846  tmp_boundary_element_pt.push_front(
12847  edge_element_pt[iproc][jproc][iiedge][0]);
12848  // Add the face elements
12849  tmp_face_index_element.push_front(
12850  edge_element_face[iproc][jproc][iiedge][1]);
12851  tmp_face_index_element.push_front(
12852  edge_element_face[iproc][jproc][iiedge][0]);
12853  }
12854 
12855  if (node_added_to_the_right)
12856  {
12857  // Add the bulk elements
12858  tmp_boundary_element_pt.push_back(
12859  edge_element_pt[iproc][jproc][iiedge][0]);
12860  tmp_boundary_element_pt.push_back(
12861  edge_element_pt[iproc][jproc][iiedge][1]);
12862  // Add the face elements
12863  tmp_face_index_element.push_back(
12864  edge_element_face[iproc][jproc][iiedge][0]);
12865  tmp_face_index_element.push_back(
12866  edge_element_face[iproc][jproc][iiedge][1]);
12867  }
12868 
12869  // Based on which side the node was added, look for
12870  // connections on that side
12871 
12872  // Verify for connections to the left (we need to
12873  // check for the connection variable too, since
12874  // after a connection has been done we no longer
12875  // need to verify for this condition)
12876  if (node_added_to_the_left && !connection_to_the_left)
12877  {
12878  // Check for connection
12879  bound_id_connection_to_the_left =
12880  check_connections_of_polyline_nodes(
12881  element_in_processor_pt,
12882  root_edge_bound_id,
12883  overlapped_edge,
12884  node_on_bnd_not_overlapped_by_shd_bnd,
12885  sorted_nodes,
12886  shared_bnd_id_to_sorted_list_node_pt,
12887  added_node_degree,
12888  new_added_node_pt);
12889 
12890  // If there is a connection then set the
12891  // corresponding flag
12892  // (-1): No connection
12893  // (-2): Connection with itself
12894  // (other value): Boundary id
12895  if (bound_id_connection_to_the_left != -1)
12896  {
12897  connection_to_the_left = true;
12898  } // if (bound_id_connection_to_the_left != -1)
12899 
12900  } // if (node_added_to_the_left &&
12901  // !connection_to_the_left)
12902 
12903  // Verify for connections to the right (we need to
12904  // check for the connection variable too, since
12905  // after a connection has been done we no longer
12906  // need to verify for this condition)
12907  if (node_added_to_the_right && !connection_to_the_right)
12908  {
12909  // Check for connection
12910  bound_id_connection_to_the_right =
12911  check_connections_of_polyline_nodes(
12912  element_in_processor_pt,
12913  root_edge_bound_id,
12914  overlapped_edge,
12915  node_on_bnd_not_overlapped_by_shd_bnd,
12916  sorted_nodes,
12917  shared_bnd_id_to_sorted_list_node_pt,
12918  added_node_degree,
12919  new_added_node_pt);
12920 
12921  // If there is a connection then set the
12922  // corresponding flag
12923  // (-1): No connection
12924  // (-2): Connection with itself
12925  // (other value): Boundary id
12926  if (bound_id_connection_to_the_right != -1)
12927  {
12928  connection_to_the_right = true;
12929  } // if (bound_id_connection_to_the_right != -1)
12930 
12931  } // if (node_added_to_the_right &&
12932  // !connection_to_the_right)
12933 
12934  // If the current shared boundary has connections
12935  // at both ends then stop the adding of nodes
12936  if (connection_to_the_left && connection_to_the_right)
12937  {current_polyline_has_connections_at_both_ends = true;}
12938 
12939  // Break the for and re-start to look more edges to
12940  // the left or right
12941  break;
12942 
12943  } // if (node_added)
12944 
12945  } // if (!edge_done[edge])
12946  } // for (iiedge < nedges)
12947 
12948  } // while(node_added && (nsorted_edges < nedges)
12949  // && !current_polyline_has_connections_at_both_ends)
12950 
12951  // ------------------------------------------------------------
12952  // If the sorted nodes of the shared polyline create a loop
12953  // it is necessary to break it by creating as many
12954  // polylines as required
12955 
12956  // Change the list to a vector representation of the
12957  // boundary elements and the face indexes
12958 
12959  // Get the number of boundary elements
12960  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
12961 
12962  // Storage for the boundary elements and face indexes
12963  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
12964  Vector<int> tmp_face_idx_ele(n_bnd_ele);
12965  // Helper counter
12966  unsigned help_counter = 0;
12967  // Fill the data structures
12968  for (std::list<FiniteElement*>::iterator it_bnd_ele =
12969  tmp_boundary_element_pt.begin();
12970  it_bnd_ele != tmp_boundary_element_pt.end();
12971  it_bnd_ele++)
12972  {
12973  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
12974  }
12975 
12976  // Restart counter
12977  help_counter = 0;
12978  for (std::list<int>::iterator it_face_idx =
12979  tmp_face_index_element.begin();
12980  it_face_idx != tmp_face_index_element.end();
12981  it_face_idx++)
12982  {
12983  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
12984  }
12985 
12986  // Store the nodes for the new shared polylines without
12987  // loops
12988  Vector<std::list<Node*> > final_sorted_nodes_pt;
12989  // Store the boundary elements of the shared polyline
12990  // without loops
12991  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
12992  // Face indexes of the boundary elements without loops
12993  Vector<Vector<int> > final_face_index_element;
12994  // Connection flags (to the left) of the shared boundaries
12995  // without loops
12996  Vector<int> final_bound_id_connection_to_the_left;
12997  // Connection flags (to the right) of the shared boundaries
12998  // without loops
12999  Vector<int> final_bound_id_connection_to_the_right;
13000 
13001  // Break any possible loop created by the shared polyline
13002  break_loops_on_shared_polyline_helper(
13003  shared_boundary_id_start,
13004  sorted_nodes,
13005  tmp_bnd_ele_pt, tmp_face_idx_ele,
13006  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
13007  final_sorted_nodes_pt,
13008  final_boundary_element_pt, final_face_index_element,
13009  final_bound_id_connection_to_the_left,
13010  final_bound_id_connection_to_the_right);
13011 
13012  // Get the number of final sorted nodes
13013  const unsigned n_final_sorted_nodes =
13014  final_sorted_nodes_pt.size();
13015 
13016  // Loop over the list of final sorted nodes
13017  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13018  {
13019  // --------------------------------------------------------
13020  // Associate the list of sorted nodes with the boundary id
13021  // of the shared boundary that is going to be crated
13022  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13023  final_sorted_nodes_pt[i];
13024 
13025  // Create the shared polyline and fill the data
13026  // structured associated to it
13027  create_shared_polyline(my_rank, shared_boundary_id_start,
13028  iproc, jproc, final_sorted_nodes_pt[i],
13029  root_edge_bound_id,
13030  final_boundary_element_pt[i],
13031  final_face_index_element[i],
13032  unsorted_polylines_pt,
13033  final_bound_id_connection_to_the_left[i],
13034  final_bound_id_connection_to_the_right[i]);
13035 
13036  // Increase the register for the number of created shared
13037  // polylines
13038  npolylines_counter++;
13039 
13040  // Increase the boundary id (the one that will be used by
13041  // the next shared boundary)
13042  shared_boundary_id_start++;
13043 
13044  } // for (i < n_final_sorted_nodes)
13045 
13046  } // while(nsorted_edges < nedges);
13047 
13048  } // for (jproc < nproc)
13049 
13050  // We already have all the shared polylines (shared boundaries)
13051  // of processor iproc with processor jproc. Now we sort them so
13052  // that they be contiguous and can create polygons.
13053 
13054  // If there are polylines to be sorted then sort them
13055  if (unsorted_polylines_pt[iproc].size() > 0)
13056  {
13057  // Now that we have all the new unsorted polylines on "iproc"
13058  // processor it is time to sort them so they be all contiguous
13059  sort_polylines_helper(unsorted_polylines_pt[iproc],
13060  output_polylines_pt[iproc]);
13061  }
13062 
13063 #ifdef PARANOID
13064  const unsigned nunsorted_polylines_iproc =
13065  unsorted_polylines_pt[iproc].size();
13066 
13067  // Verify that all the polylines have been sorted
13068  unsigned tmp_ntotal_polylines = 0;
13069  // Count the total number of sorted polylines
13070  for (unsigned ii = 0 ; ii < output_polylines_pt[iproc].size(); ii++)
13071  {tmp_ntotal_polylines+= output_polylines_pt[iproc][ii].size();}
13072  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13073  {
13074  std::ostringstream error_message;
13075  error_message
13076  <<" The total number of unsorted polylines ("
13077  << nunsorted_polylines_iproc << ") in common with\nprocessor ("
13078  << iproc<< ") is different from the total number of sorted "
13079  << "polylines (" << tmp_ntotal_polylines << ") with\nthe same "
13080  << "proessor\n";
13081  throw OomphLibError(error_message.str(),
13082  OOMPH_CURRENT_FUNCTION,
13083  OOMPH_EXCEPTION_LOCATION);
13084  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13085 #endif
13086 
13087  } // for (iproc < nproc)
13088 
13089  // Establish the last used boundary id
13090  this->Final_shared_boundary_id = shared_boundary_id_start;
13091 
13092  }
13093 
13094  // ======================================================================
13095  // \short Break any possible loop created by the sorted list of nodes
13096  // that is used to create a new shared polyline
13097  // ======================================================================
13098  template<class ELEMENT>
13100  const unsigned &initial_shd_bnd_id,
13101  std::list<Node*> &input_nodes,
13102  Vector<FiniteElement*> &input_boundary_element_pt,
13103  Vector<int> &input_face_index_element,
13104  const int &input_connect_to_the_left,
13105  const int &input_connect_to_the_right,
13106  Vector<std::list<Node*> > &output_sorted_nodes_pt,
13107  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
13108  Vector<Vector<int> > &output_face_index_element,
13109  Vector<int> &output_connect_to_the_left,
13110  Vector<int> &output_connect_to_the_right)
13111  {
13112  // Get the left and right node of the current list of sorted nodes
13113  Node* left_node_pt = input_nodes.front();
13114  Node* right_node_pt = input_nodes.back();
13115 
13116  // Temporary storage for list of nodes, boundary elements and face
13117  // element's indexes
13118  Vector<std::list<Node*> > tmp_sub_nodes;
13119  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
13120  Vector<Vector<int> > tmp_sub_face_idx_ele;
13121 
13122  // Iterator for the list of input nodes
13123  std::list<Node*>::iterator it = input_nodes.begin();
13124 
13125  // Counter
13126  unsigned counter = 0;
13127 
13128  // Loop while not all nodes have been done
13129  while(it != input_nodes.end())
13130  {
13131  // Check if the current node is the final one
13132  it++;
13133  // Is the current node the final node?
13134  if (it == input_nodes.end())
13135  {
13136  // Break, add no more nodes
13137  break;
13138  }
13139  else
13140  {
13141  // Restore the iterator
13142  it--;
13143  }
13144 
13145  // Get a list of nonrepeated nodes
13146  std::list<Node*> sub_nodes;
13147  // The temporary vector of boundary elements associated with the
13148  // nodes
13149  Vector<FiniteElement*> sub_bnd_ele_pt;
13150  // The temporary vector of face indexes associated with the
13151  // boundary elements
13152  Vector<int> sub_face_idx_ele;
13153 
13154  // Add the current node to the list
13155  sub_nodes.push_back(*it);
13156 
13157  // Add nodes until found a repeated node (the left or right
13158  // node) or until reaching the end of the list of nodes
13159  do
13160  {
13161  // Go to the next node
13162  ++it;
13163 
13164  // Add the new node
13165  sub_nodes.push_back((*it));
13166 
13167  // Add the boundary elements
13168  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13169  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter+1]);
13170 
13171  // Add the face indexes
13172  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13173  sub_face_idx_ele.push_back(input_face_index_element[counter+1]);
13174 
13175  // Increase the counter
13176  counter+=2;
13177 
13178  // Continue adding until reaching a repeated node or the end
13179  // of the list of nodes
13180  }while((*it) != left_node_pt &&
13181  (*it) != right_node_pt &&
13182  it != input_nodes.end());
13183 
13184  // Add the sub-set of nodes to the temporary storage
13185  tmp_sub_nodes.push_back(sub_nodes);
13186  // Add the face elements to the temporary storage
13187  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13188  // Add the face indexes to the temporary storage
13189  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13190 
13191  } // while((*it) != input_nodes.end())
13192 
13193  // --------------------------------------------------
13194  // Now create as many shared boundaries as required
13195 
13196  // Get the number of sub-list of nodes created
13197  const unsigned n_sub_list = tmp_sub_nodes.size();
13198 
13199 #ifdef PARANOID
13200  if (n_sub_list > 3)
13201  {
13202  std::stringstream error_message;
13203  error_message
13204  << "The number of sub-list of nodes created from the shared\n"
13205  << "polyline with loops was (" << n_sub_list << ").\n"
13206  << "We can only handle up to three sub-list of nodes\n";
13207  throw OomphLibError(error_message.str(),
13208  OOMPH_CURRENT_FUNCTION,
13209  OOMPH_EXCEPTION_LOCATION);
13210  }
13211 #endif
13212 
13213  // If there is only one list it may be because there are no loops or
13214  // there is only one loop (a circle)
13215  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13216  {
13217  // There are no loops, return just after filling the data
13218  // structures
13219 
13220  // This is the base case used most of the times
13221 
13222  // Set the vector of lists of nodes
13223  output_sorted_nodes_pt = tmp_sub_nodes;
13224  // Set the vector of boundary elements
13225  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13226  // Set the vector of face indexes
13227  output_face_index_element = tmp_sub_face_idx_ele;
13228 
13229  // Set the connection flags, change them by the proper connection
13230  // flag
13231 
13232 #ifdef PARANOID
13233  if (input_connect_to_the_left == -2)
13234  {
13235  std::stringstream error_message;
13236  error_message
13237  << "The connection flag to the left ("
13238  << input_connect_to_the_left << ") indicates a connection\n"
13239  << "with the same polyline.\n However, only one sub-polyline was "
13240  << "found and no loop\nwas identified\n\n";
13241  throw OomphLibError(error_message.str(),
13242  OOMPH_CURRENT_FUNCTION,
13243  OOMPH_EXCEPTION_LOCATION);
13244  }
13245 #endif
13246 
13247  // The left connection flag
13248  if (input_connect_to_the_left == -3)
13249  {
13250  output_connect_to_the_left.push_back(-1);
13251  }
13252  else
13253  {
13254  output_connect_to_the_left.push_back(input_connect_to_the_left);
13255  }
13256 
13257 #ifdef PARANOID
13258  if (input_connect_to_the_right == -2)
13259  {
13260  std::stringstream error_message;
13261  error_message
13262  << "The connection flag to the right ("
13263  << input_connect_to_the_right << ") indicates a connection\n"
13264  << "with the same polyline.\n However, only one sub-polyline was "
13265  << "found and no loop\nwas identified\n\n";
13266  throw OomphLibError(error_message.str(),
13267  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13268  OOMPH_EXCEPTION_LOCATION);
13269  }
13270 #endif
13271 
13272  // The right connection flag
13273  if (input_connect_to_the_right == -3)
13274  {
13275  output_connect_to_the_right.push_back(-1);
13276  }
13277  else
13278  {
13279  output_connect_to_the_right.push_back(input_connect_to_the_right);
13280  }
13281 
13282  // Return inmediately
13283  return;
13284  }
13285 
13286  // The temporary storage for the shared boundary id
13287  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13288 
13289  // -----------------------------------------------------------------
13290  // Check all the sub-list of nodes and create two shared boundaries
13291  // from those that make a loop (circle)
13292 
13293  // -----------------------------------------------------------
13294  // Get the left and right node of the first sub-list of nodes
13295  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13296  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13297 
13298  // Check if the sub-list of nodes creates a loop (circle)
13299  if (left_sub_node_pt == right_sub_node_pt)
13300  {
13301  // We need to create two shared polylines and therefore increase
13302  // the shared boundary id by two
13303 
13304  // The first and second half of nodes
13305  std::list<Node*> first_half_node_pt;
13306  std::list<Node*> second_half_node_pt;
13307  // The first and second half of boundary elements
13308  Vector<FiniteElement*> first_half_ele_pt;
13309  Vector<FiniteElement*> second_half_ele_pt;
13310  // The first and second half of face indexes
13311  Vector<int> first_half_face_idx;
13312  Vector<int> second_half_face_idx;
13313 
13314  // Get the number of sub-nodes in the sub-list of nodes
13315  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13316 
13317  // The number of sub-nodes for the first half of the shared
13318  // boundary
13319  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13320 
13321  // Copy as many sub-nodes for the first half of the sub-polyline
13322 
13323  // Iterator to loop over the nodes
13324  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13325 
13326  // Add the first node
13327  first_half_node_pt.push_back(*it_sub);
13328 
13329  // Skip the first node
13330  it_sub++;
13331 
13332  // Counter
13333  unsigned counter_nodes = 0;
13334  unsigned counter2 = 0;
13335 
13336  // Loop to copy the nodes
13337  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13338  {
13339  // Add the sub-node to the first half
13340  first_half_node_pt.push_back(*it_sub);
13341 
13342  // Add the boundary elements of the first half
13343  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13344  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13345  // Add the face indexes of the first half
13346  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13347  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13348 
13349  // Increase the counter of added nodes
13350  counter_nodes++;
13351 
13352  // Increase the other counter
13353  counter2+=2;
13354 
13355  if (counter_nodes == n_sub_nodes_half)
13356  {
13357  // Stop adding to the first half of nodes
13358  break;
13359  }
13360 
13361  } // Copy the first half of nodes
13362 
13363  // The second half
13364 
13365  // Add the first node of the second half
13366  second_half_node_pt.push_back(*it_sub);
13367 
13368  // Skip the first node of the second half
13369  it_sub++;
13370 
13371  // Loop to copy the nodes
13372  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13373  {
13374  // Add the sub-node to the first half
13375  second_half_node_pt.push_back(*it_sub);
13376 
13377  // Add the boundary elements of the first half
13378  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13379  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13380  // Add the face indexes of the first half
13381  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13382  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13383 
13384  // Increase the other counter
13385  counter2+=2;
13386 
13387  } // Copy the second half of nodes
13388 
13389  // Add the sub-list of nodes to the vector of lists of nodes
13390  output_sorted_nodes_pt.push_back(first_half_node_pt);
13391  output_sorted_nodes_pt.push_back(second_half_node_pt);
13392  // Add the sub-vector of elements to the vector of boundary
13393  // elements
13394  output_boundary_element_pt.push_back(first_half_ele_pt);
13395  output_boundary_element_pt.push_back(second_half_ele_pt);
13396  // Add the sub-vector of face indexes to the vector of face
13397  // indexes
13398  output_face_index_element.push_back(first_half_face_idx);
13399  output_face_index_element.push_back(second_half_face_idx);
13400 
13401  // Set the connection flags, change them by the proper connection
13402  // flag
13403 
13404  // ----------------------------------------------------------------
13405  // Connections flags for the first half
13406 
13407  // The left connection flag
13408 
13409  // Connected with nothing but required to stop adding nodes
13410  if (input_connect_to_the_left == -3)
13411  {
13412  // Set connected to nothing
13413  output_connect_to_the_left.push_back(-1);
13414  }
13415  // Connected with itself
13416  else if (input_connect_to_the_left == -2)
13417  {
13418  // Set connected to nothing, this is the base node
13419  output_connect_to_the_left.push_back(-1);
13420  }
13421  else
13422  {
13423  // Any other value keep it
13424  output_connect_to_the_left.push_back(input_connect_to_the_left);
13425  }
13426 
13427  // The right connection flag
13428 
13429  // Set connected to nothing, this is the base node
13430  output_connect_to_the_right.push_back(-1);
13431 
13432  // Increase the shared boundary id
13433  tmp_shd_bnd_id++;
13434 
13435  // ----------------------------------------------------------------
13436  // Connections flags for the second half
13437 
13438  // The left connection flag
13439 
13440  // Set connected to the previous boundary
13441  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13442 
13443  // The right connection flag
13444 
13445  // Are we in the last sub-list of nodes, if that is the case we
13446  // need to respect the flag assigned to the right
13447  if (n_sub_list == 1)
13448  {
13449  if (input_connect_to_the_right == -3)
13450  {
13451  // Set connected to the previous shared boundary id
13452  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13453  }
13454  else if (input_connect_to_the_right == -2)
13455  {
13456  // Set connected to the previous shared boundary id
13457  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13458  }
13459  else if (input_connect_to_the_right == -1)
13460  {
13461  // Set connected to the previous shared boundary id
13462  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13463  }
13464  else
13465  {
13466  // Any other value keep it
13467  output_connect_to_the_right.push_back(input_connect_to_the_right);
13468  }
13469  } // if (n_sub_list == 1)
13470  else
13471  {
13472  // Set connected to the previous shared boundary id
13473  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13474  }
13475 
13476  // Increase the shared boundary id
13477  tmp_shd_bnd_id++;
13478 
13479  } // if (left_sub_node_pt == right_sub_node_pt)
13480  else
13481  {
13482  // No need to create two boundaries, create only one with the
13483  // sub-list of nodes
13484 
13485  // Add the sub-list of nodes to the vector of lists of nodes
13486  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13487  // Add the sub-vector of elements to the vector of boundary
13488  // elements
13489  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13490  // Add the sub-vector of face indexes to the vector of face
13491  // indexes
13492  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13493 
13494  // Set the connection flags, change them by the proper connection
13495  // flag
13496 
13497  // The left connection flag
13498 
13499  // Connected with nothing but required to stop adding nodes
13500  if (input_connect_to_the_left == -3)
13501  {
13502  // Set to connected to nothing
13503  output_connect_to_the_left.push_back(-1);
13504  }
13505  // Connected with itself
13506  else if (input_connect_to_the_left == -2)
13507  {
13508  // Set connected to the next shared polyline id
13509  output_connect_to_the_left.push_back(tmp_shd_bnd_id+1);
13510  }
13511  else
13512  {
13513  // Any other value keep it
13514  output_connect_to_the_left.push_back(input_connect_to_the_left);
13515  }
13516 
13517  // The right connection flag
13518 
13519  // Set connected to the next shared polyline id
13520  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13521 
13522  // Increase the shared boundary id by one
13523  tmp_shd_bnd_id++;
13524 
13525  } // else if (left_sub_node_pt == right_sub_node_pt)
13526 
13527  // At least two sub-list of nodes were created
13528  if (n_sub_list > 1)
13529  {
13530  // ------------------------------------------------------------
13531  // Get the left and right node of the second sub-list of nodes
13532  left_sub_node_pt = tmp_sub_nodes[1].front();
13533  right_sub_node_pt = tmp_sub_nodes[1].back();
13534 
13535  // Check if the sub-list of nodes creates a loop (circle)
13536  if (left_sub_node_pt == right_sub_node_pt)
13537  {
13538  // We need to create two shared polylines and therefore increase
13539  // the shared boundary id by two
13540 
13541  // The first and second half of nodes
13542  std::list<Node*> first_half_node_pt;
13543  std::list<Node*> second_half_node_pt;
13544  // The first and second half of boundary elements
13545  Vector<FiniteElement*> first_half_ele_pt;
13546  Vector<FiniteElement*> second_half_ele_pt;
13547  // The first and second half of face indexes
13548  Vector<int> first_half_face_idx;
13549  Vector<int> second_half_face_idx;
13550 
13551  // Get the number of sub-nodes in the sub-list of nodes
13552  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13553 
13554  // The number of sub-nodes for the first half of the shared
13555  // boundary
13556  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13557 
13558  // Copy as many sub-nodes for the first half of the sub-polyline
13559 
13560  // Iterator to loop over the nodes
13561  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13562 
13563  // Add the first node
13564  first_half_node_pt.push_back(*it_sub);
13565 
13566  // Skip the first node
13567  it_sub++;
13568 
13569  // Counter
13570  unsigned counter_nodes = 0;
13571  unsigned counter2 = 0;
13572 
13573  // Loop to copy the nodes
13574  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13575  {
13576  // Add the sub-node to the first half
13577  first_half_node_pt.push_back(*it_sub);
13578  // Add the boundary elements of the first half
13579  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13580  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13581  // Add the face indexes of the first half
13582  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13583  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13584 
13585  // Increase the counter of added nodes
13586  counter_nodes++;
13587 
13588  // Increase the other counter
13589  counter2+=2;
13590 
13591  if (counter_nodes == n_sub_nodes_half)
13592  {
13593  // Stop adding to the first half of nodes
13594  break;
13595  }
13596 
13597  } // Copy the first half of nodes
13598 
13599  // The second half
13600 
13601  // Add the first node of the second half
13602  second_half_node_pt.push_back(*it_sub);
13603 
13604  // Skip the first node of the second half
13605  it_sub++;
13606 
13607  // Loop to copy the nodes
13608  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13609  {
13610  // Add the sub-node to the first half
13611  second_half_node_pt.push_back(*it_sub);
13612  // Add the boundary elements of the first half
13613  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13614  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13615  // Add the face indexes of the first half
13616  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13617  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13618 
13619  // Increase the other counter
13620  counter2+=2;
13621 
13622  } // Copy the second half of nodes
13623 
13624  // Add the sub-list of nodes to the vector of lists of nodes
13625  output_sorted_nodes_pt.push_back(first_half_node_pt);
13626  output_sorted_nodes_pt.push_back(second_half_node_pt);
13627  // Add the sub-vector of elements to the vector of boundary
13628  // elements
13629  output_boundary_element_pt.push_back(first_half_ele_pt);
13630  output_boundary_element_pt.push_back(second_half_ele_pt);
13631  // Add the sub-vector of face indexes to the vector of face
13632  // indexes
13633  output_face_index_element.push_back(first_half_face_idx);
13634  output_face_index_element.push_back(second_half_face_idx);
13635 
13636  // Set the connection flags, change them by the proper
13637  // connection flag
13638 
13639  // --------------------------------------
13640  // Connections flags for the first half
13641 
13642  // The left connection flag
13643 
13644  // Connected to the previous boundary
13645  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13646 
13647  // The right connection flag
13648 
13649  // Set connected to nothing, this is the base node
13650  output_connect_to_the_right.push_back(-1);
13651 
13652  // Increase the shared boundary id
13653  tmp_shd_bnd_id++;
13654 
13655  // --------------------------------------
13656  // Connections flags for the second half
13657 
13658  // The left connection flag
13659 
13660  // Set connected to the previous boundary
13661  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13662 
13663  // The right connection flag
13664 
13665  // Are we in the last sub-list of nodes, if that is the case we
13666  // need to respect the flag assigned to the right
13667  if (n_sub_list == 2)
13668  {
13669  // Connected with nothing
13670  if (input_connect_to_the_right == -1)
13671  {
13672  // Set connected to the previous shared boundary
13673  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13674  }
13675  // Connected with the same boundary
13676  else if (input_connect_to_the_right == -2)
13677  {
13678  // Set connected to the previous shared boundary
13679  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13680  }
13681  // Connetted with nothing but stop adding nodes
13682  else if (input_connect_to_the_right == -3)
13683  {
13684  // Set connected to the previous shared boundary
13685  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13686  }
13687  else
13688  {
13689  // Any other value keep it
13690  output_connect_to_the_right.push_back(input_connect_to_the_right);
13691  }
13692 
13693  // Increase the shared boundary id
13694  tmp_shd_bnd_id++;
13695 
13696  } // if (n_sub_list == 2)
13697 #ifdef PARANOID
13698  else
13699  {
13700  std::stringstream error_message;
13701  error_message
13702  << "The second sub-list of nodes creates a loop but this is not\n"
13703  << "the last list of sub-nodes.\n"
13704  << "This configuration is not supported\n";
13705  throw OomphLibError(error_message.str(),
13706  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13707  OOMPH_EXCEPTION_LOCATION);
13708  }
13709 #endif
13710 
13711  } // if (left_sub_node_pt == right_sub_node_pt)
13712  else
13713  {
13714  // No need to create two boundaries, create only one with the
13715  // sub-list of nodes
13716 
13717  // Add the sub-list of nodes to the vector of lists of nodes
13718  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13719  // Add the sub-vector of elements to the vector of boundary
13720  // elements
13721  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13722  // Add the sub-vector of face indexes to the vector of face
13723  // indexes
13724  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13725 
13726  // Set the connection flags, change them by the proper connection
13727  // flag
13728 
13729  // The left connection flag
13730 
13731  // Set connected to the previous shared boundary id
13732  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13733 
13734  // The right connection flag
13735 
13736  // Are we in the last sub-list of nodes, if that is the case we
13737  // need to respect the flag assigned to the right
13738  if (n_sub_list == 2)
13739  {
13740  // Connected with nothing but required to stop adding nodes
13741  if (input_connect_to_the_right == -3)
13742  {
13743  // Set to connected to nothing
13744  output_connect_to_the_right.push_back(-1);
13745  }
13746 #ifdef PARANOID
13747  // Connected with itself
13748  else if (input_connect_to_the_right == -2)
13749  {
13750  std::stringstream error_message;
13751  error_message
13752  << "The connection flag to the right ("
13753  << input_connect_to_the_right << ") indicates a connection\n"
13754  << "with the same polyline.\n However, the second sub-list of\n"
13755  << "nodes was found not making a loop so no connection with\n"
13756  << "itself should be marked\n\n";
13757  throw OomphLibError(error_message.str(),
13758  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13759  OOMPH_EXCEPTION_LOCATION);
13760  }
13761 #endif
13762  else
13763  {
13764  // Any other value keep it
13765  output_connect_to_the_right.push_back(input_connect_to_the_right);
13766  }
13767  } // if (n_sub_list == 2)
13768  else
13769  {
13770  // Set connected to the next shared boundary id
13771  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13772  } // else if (n_sub_list == 2)
13773 
13774  // Increase the shared boundary id by one
13775  tmp_shd_bnd_id++;
13776 
13777  } // if (left_sub_node_pt == right_sub_node_pt)
13778 
13779  } // if (n_sub_list > 1)
13780 
13781  // Three sub-list of nodes were created
13782  if (n_sub_list > 2)
13783  {
13784  // ------------------------------------------------------------
13785  // Get the left and right node of the third sub-list of nodes
13786  left_sub_node_pt = tmp_sub_nodes[2].front();
13787  right_sub_node_pt = tmp_sub_nodes[2].back();
13788 
13789  // Check if the sub-list of nodes creates a loop (circle)
13790  if (left_sub_node_pt == right_sub_node_pt)
13791  {
13792  // We need to create two shared polylines and therefore increase
13793  // the shared boundary id by two
13794 
13795  // The first and second half of nodes
13796  std::list<Node*> first_half_node_pt;
13797  std::list<Node*> second_half_node_pt;
13798  // The first and second half of boundary elements
13799  Vector<FiniteElement*> first_half_ele_pt;
13800  Vector<FiniteElement*> second_half_ele_pt;
13801  // The first and second half of face indexes
13802  Vector<int> first_half_face_idx;
13803  Vector<int> second_half_face_idx;
13804 
13805  // Get the number of sub-nodes in the sub-list of nodes
13806  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13807 
13808  // The number of sub-nodes for the first half of the shared
13809  // boundary
13810  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13811 
13812  // Copy as many sub-nodes for the first half of the sub-polyline
13813 
13814  // Iterator to loop over the nodes
13815  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13816 
13817  // Add the first node
13818  first_half_node_pt.push_back(*it_sub);
13819 
13820  // Skip the first node
13821  it_sub++;
13822 
13823  // Counter
13824  unsigned counter_nodes = 0;
13825  unsigned counter2 = 0;
13826 
13827  // Loop to copy the nodes
13828  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13829  {
13830  // Add the sub-node to the first half
13831  first_half_node_pt.push_back(*it_sub);
13832  // Add the boundary elements of the first half
13833  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13834  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13835  // Add the face indexes of the first half
13836  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13837  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13838 
13839  // Increase the counter of added nodes
13840  counter_nodes++;
13841 
13842  // Increase the other counter
13843  counter2+=2;
13844 
13845  if (counter_nodes == n_sub_nodes_half)
13846  {
13847  // Stop adding to the first half of nodes
13848  break;
13849  }
13850 
13851  } // Copy the first half of nodes
13852 
13853  // The second half
13854 
13855  // Add the first node of the second half
13856  second_half_node_pt.push_back(*it_sub);
13857 
13858  // Skip the first node of the second half
13859  it_sub++;
13860 
13861  // Loop to copy the nodes
13862  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13863  {
13864  // Add the sub-node to the first half
13865  second_half_node_pt.push_back(*it_sub);
13866  // Add the boundary elements of the first half
13867  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13868  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13869  // Add the face indexes of the first half
13870  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13871  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13872 
13873  // Increase the other counter
13874  counter2+=2;
13875 
13876  } // Copy the second half of nodes
13877 
13878  // Add the sub-list of nodes to the vector of lists of nodes
13879  output_sorted_nodes_pt.push_back(first_half_node_pt);
13880  output_sorted_nodes_pt.push_back(second_half_node_pt);
13881  // Add the sub-vector of elements to the vector of boundary
13882  // elements
13883  output_boundary_element_pt.push_back(first_half_ele_pt);
13884  output_boundary_element_pt.push_back(second_half_ele_pt);
13885  // Add the sub-vector of face indexes to the vector of face
13886  // indexes
13887  output_face_index_element.push_back(first_half_face_idx);
13888  output_face_index_element.push_back(second_half_face_idx);
13889 
13890  // --------------------------------------
13891  // Connections flags for the first half
13892 
13893  // The left connection flag
13894 
13895  // Connected to the previous shared boundary
13896  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13897 
13898  // The right connection flag
13899 
13900  // Set connected to nothing, this is the base node
13901  output_connect_to_the_right.push_back(-1);
13902 
13903  // Increase the shared boundary id
13904  tmp_shd_bnd_id++;
13905 
13906  // --------------------------------------
13907  // Connections flags for the second half
13908 
13909  // The left connection flag
13910 
13911  // Set connected to the previous boundary
13912  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13913 
13914  // The right connection flag
13915 
13916  if (input_connect_to_the_right == -3)
13917  {
13918  // Set connected to the previous shared boundary id
13919  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13920  }
13921  else if (input_connect_to_the_right == -2)
13922  {
13923  // Set connected to the previous shared boundary id
13924  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13925  }
13926  else if (input_connect_to_the_right == -1)
13927  {
13928  // Set connected to the previous shared boundary id
13929  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13930  }
13931  else
13932  {
13933  // Any other value keep it
13934  output_connect_to_the_right.push_back(input_connect_to_the_right);
13935  }
13936 
13937  // Increase the shared boundary id
13938  tmp_shd_bnd_id++;
13939 
13940  } // if (left_sub_node_pt == right_sub_node_pt)
13941  else
13942  {
13943  // No need to create two boundaries, create only one with the
13944  // sub-list of nodes
13945 
13946  // Add the sub-list of nodes to the vector of lists of nodes
13947  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
13948  // Add the sub-vector of elements to the vector of boundary
13949  // elements
13950  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
13951  // Add the sub-vector of face indexes to the vector of face
13952  // indexes
13953  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
13954 
13955  // Set the connection flags, change them by the proper
13956  // connection flag
13957 
13958  // The left connection flag
13959 
13960  // Set connected to the previous shared boundary id
13961  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13962 
13963  // The right connection flag
13964 
13965  // Connected with nothing but required to stop adding nodes
13966  if (input_connect_to_the_right == -3)
13967  {
13968  std::stringstream error_message;
13969  error_message
13970  << "The connection flag to the right ("
13971  << input_connect_to_the_right << ") indicates 'no connection and\n"
13972  << "stop adding nodes'.\n However, the thrid sub-list of\n"
13973  << "nodes must have a connection to the right with the same\n"
13974  << "shared polyline or with any other polyline\n\n";
13975  throw OomphLibError(error_message.str(),
13976  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13977  OOMPH_EXCEPTION_LOCATION);
13978  }
13979  else if (input_connect_to_the_right == -1)
13980  {
13981  std::stringstream error_message;
13982  error_message
13983  << "The connection flag to the right ("
13984  << input_connect_to_the_right << ") indicates 'no connection.\n"
13985  << "However, the thrid sub-list of nodes must have a connection\n"
13986  << "to the right with the same shared polyline or with any other\n"
13987  << "polyline\n\n";
13988  throw OomphLibError(error_message.str(),
13989  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13990  OOMPH_EXCEPTION_LOCATION);
13991  }
13992  // Connected with itself
13993  else if (input_connect_to_the_right == -2)
13994  {
13995  // Set connected to the previous shared boundary id
13996  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13997  }
13998  else
13999  {
14000  // Any other value keep it
14001  output_connect_to_the_right.push_back(input_connect_to_the_right);
14002  }
14003 
14004  // Increase the shared boundary id by one
14005  tmp_shd_bnd_id++;
14006 
14007  } // if (left_sub_node_pt == right_sub_node_pt)
14008 
14009  } // if (n_sub_list > 2)
14010 
14011  }
14012 
14013  // ======================================================================
14014  // \short Break any possible loop created by the sorted list of nodes
14015  // that is used to create a new shared polyline
14016  // ======================================================================
14017  template<class ELEMENT>
14020  const unsigned &initial_shd_bnd_id,
14021  std::list<Node*> &input_nodes,
14022  Vector<FiniteElement*> &input_boundary_element_pt,
14023  Vector<FiniteElement*> &input_boundary_face_element_pt,
14024  Vector<int> &input_face_index_element,
14025  const int &input_connect_to_the_left,
14026  const int &input_connect_to_the_right,
14027  Vector<std::list<Node*> > &output_sorted_nodes_pt,
14028  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
14029  Vector<Vector<FiniteElement*> > &output_boundary_face_element_pt,
14030  Vector<Vector<int> > &output_face_index_element,
14031  Vector<int> &output_connect_to_the_left,
14032  Vector<int> &output_connect_to_the_right)
14033  {
14034  // Get the left and right node of the current list of sorted nodes
14035  Node* left_node_pt = input_nodes.front();
14036  Node* right_node_pt = input_nodes.back();
14037 
14038  // Temporary storage for list of nodes, boundary elements, boundary
14039  // face elements and face element's indexes
14040  Vector<std::list<Node*> > tmp_sub_nodes;
14041  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
14042  Vector<Vector<FiniteElement*> > tmp_sub_bnd_face_ele_pt;
14043  Vector<Vector<int> > tmp_sub_face_idx_ele;
14044 
14045  // Iterator for the list of input nodes
14046  std::list<Node*>::iterator it = input_nodes.begin();
14047 
14048  // Counter
14049  unsigned counter = 0;
14050 
14051  // Loop while not all nodes have been done
14052  while(it != input_nodes.end())
14053  {
14054  // Check if the current node is the final one
14055  it++;
14056  // Is the current node the final node?
14057  if (it == input_nodes.end())
14058  {
14059  // Break, add no more nodes
14060  break;
14061  }
14062  else
14063  {
14064  // Restore the iterator
14065  it--;
14066  }
14067 
14068  // Get a list of nonrepeated nodes
14069  std::list<Node*> sub_nodes;
14070  // The temporary vector of boundary elements associated with the
14071  // nodes
14072  Vector<FiniteElement*> sub_bnd_ele_pt;
14073  // The temporary vector of boundary face elements associated with
14074  // the nodes
14075  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14076  // The temporary vector of face indexes associated with the
14077  // boundary elements
14078  Vector<int> sub_face_idx_ele;
14079 
14080  // Add the current node to the list
14081  sub_nodes.push_back(*it);
14082 
14083  // Add nodes until found a repeated node (the left or right
14084  // node) or until reaching the end of the list of nodes
14085  do
14086  {
14087  // Go to the next node
14088  ++it;
14089 
14090  // Add the new node
14091  sub_nodes.push_back((*it));
14092 
14093  // Add the boundary elements
14094  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14095 
14096  // Add the boundary face elements
14097  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14098 
14099  // Add the face indexes
14100  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14101 
14102  // Increase the counter
14103  counter++;
14104 
14105  // Continue adding until reaching a repeated node or the end
14106  // of the list of nodes
14107  }while((*it) != left_node_pt &&
14108  (*it) != right_node_pt &&
14109  it != input_nodes.end());
14110 
14111  // Add the sub-set of nodes to the temporary storage
14112  tmp_sub_nodes.push_back(sub_nodes);
14113 
14114  // Add the boundary elements to the temporary storage
14115  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14116  // Add the boundary face elements to the temporary storage
14117  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14118  // Add the face indexes to the temporary storage
14119  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14120 
14121  } // while((*it) != input_nodes.end())
14122 
14123  // --------------------------------------------------
14124  // Now create as many shared boundaries as required
14125 
14126  // Get the number of sub-list of nodes created
14127  const unsigned n_sub_list = tmp_sub_nodes.size();
14128 
14129 #ifdef PARANOID
14130  if (n_sub_list > 1)
14131  {
14132  std::stringstream error_message;
14133  error_message
14134  << "The number of sub-list of nodes created from the shared\n"
14135  << "polyline with loops was (" << n_sub_list << ").\n"
14136  << "We can only handle one list which may still contain loops\n"
14137  << "(or repeated nodes)\n";
14138  throw OomphLibError(error_message.str(),
14139  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14140  OOMPH_EXCEPTION_LOCATION);
14141  }
14142 #endif
14143 
14144  // If there is only one list it may be because there are no loops or
14145  // there is only one loop (a circle)
14146  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14147  {
14148  // There are no loops, return just after filling the data
14149  // structures
14150 
14151  // This is the base case used most of the times
14152 
14153  // Set the vector of lists of nodes
14154  output_sorted_nodes_pt = tmp_sub_nodes;
14155  // Set the vector of boundary elements
14156  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14157  // Set the vector of boundary face elements
14158  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14159  // Set the vector of face indexes
14160  output_face_index_element = tmp_sub_face_idx_ele;
14161 
14162  // Set the connection flags, change them by the proper connection
14163  // flag
14164 
14165 #ifdef PARANOID
14166  if (input_connect_to_the_left == -2)
14167  {
14168  std::stringstream error_message;
14169  error_message
14170  << "The connection flag to the left ("
14171  << input_connect_to_the_left << ") indicates a connection\n"
14172  << "with the same polyline.\n However, only one sub-polyline was "
14173  << "found and no loops\nwere identified\n\n";
14174  throw OomphLibError(error_message.str(),
14175  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14176  OOMPH_EXCEPTION_LOCATION);
14177  }
14178 #endif
14179 
14180  // The left connection flag
14181  if (input_connect_to_the_left == -3)
14182  {
14183  output_connect_to_the_left.push_back(-1);
14184  }
14185  else
14186  {
14187  output_connect_to_the_left.push_back(input_connect_to_the_left);
14188  }
14189 
14190 #ifdef PARANOID
14191  if (input_connect_to_the_right == -2)
14192  {
14193  std::stringstream error_message;
14194  error_message
14195  << "The connection flag to the right ("
14196  << input_connect_to_the_right << ") indicates a connection\n"
14197  << "with the same polyline.\n However, only one sub-polyline was "
14198  << "found and no loops\nwere identified\n\n";
14199  throw OomphLibError(error_message.str(),
14200  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14201  OOMPH_EXCEPTION_LOCATION);
14202  }
14203 #endif
14204 
14205  // The right connection flag
14206  if (input_connect_to_the_right == -3)
14207  {
14208  output_connect_to_the_right.push_back(-1);
14209  }
14210  else
14211  {
14212  output_connect_to_the_right.push_back(input_connect_to_the_right);
14213  }
14214 
14215  // Return immediately
14216  return;
14217  }
14218 
14219  // The temporary storage for the shared boundary id
14220  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14221 
14222  // -----------------------------------------------------------------
14223  // Check all the sub-list of nodes and create two shared boundaries
14224  // from those that make a loop (circle)
14225 
14226  // -----------------------------------------------------------
14227  // Get the left and right node of the first sub-list of nodes
14228  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14229  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14230 
14231  // Check if the sub-list of nodes creates a loop (circle)
14232  if (left_sub_node_pt == right_sub_node_pt)
14233  {
14234  // We need to create two shared polylines and therefore increase
14235  // the shared boundary id by two
14236 
14237  // The first and second half of nodes
14238  std::list<Node*> first_half_node_pt;
14239  std::list<Node*> second_half_node_pt;
14240  // The first and second half of boundary elements
14241  Vector<FiniteElement*> first_half_ele_pt;
14242  Vector<FiniteElement*> second_half_ele_pt;
14243  // The first and second half of boundary face elements
14244  Vector<FiniteElement*> first_half_ele_face_pt;
14245  Vector<FiniteElement*> second_half_ele_face_pt;
14246  // The first and second half of face indexes
14247  Vector<int> first_half_face_idx;
14248  Vector<int> second_half_face_idx;
14249 
14250  // Get the number of sub-nodes in the sub-list of nodes
14251  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14252 
14253  // The number of sub-nodes for the first half of the shared
14254  // boundary
14255  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
14256 
14257  // Copy as many sub-nodes for the first half of the sub-polyline
14258 
14259  // Iterator to loop over the nodes
14260  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14261 
14262  // Add the first node
14263  first_half_node_pt.push_back(*it_sub);
14264 
14265  // Skip the first node
14266  it_sub++;
14267 
14268  // Counter
14269  unsigned counter_nodes = 0;
14270  unsigned counter2 = 0;
14271 
14272  // Loop to copy the nodes
14273  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14274  {
14275  // Add the sub-node to the first half
14276  first_half_node_pt.push_back(*it_sub);
14277 
14278  // Add the boundary elements of the first half
14279  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14280  // Add the boundary face elements of the first half
14281  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14282  // Add the face indexes of the first half
14283  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14284 
14285  // Increase the counter of added nodes
14286  counter_nodes++;
14287 
14288  // Increase the other counter (of the elements/face)
14289  counter2++;
14290 
14291  if (counter_nodes == n_sub_nodes_half)
14292  {
14293  // Stop adding to the first half of nodes
14294  break;
14295  }
14296 
14297  } // Copy the first half of nodes
14298 
14299  // The second half
14300 
14301  // Add the first node of the second half
14302  second_half_node_pt.push_back(*it_sub);
14303 
14304  // Skip the first node of the second half
14305  it_sub++;
14306 
14307  // Loop to copy the nodes
14308  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14309  {
14310  // Add the sub-node to the first half
14311  second_half_node_pt.push_back(*it_sub);
14312 
14313  // Add the boundary elements of the first half
14314  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14315  // Add the boundary face elements of the first half
14316  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14317  // Add the face indexes of the first half
14318  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14319 
14320  // Increase the other counter
14321  counter2++;
14322 
14323  } // Copy the second half of nodes
14324 
14325  // Add the sub-list of nodes to the vector of lists of nodes
14326  output_sorted_nodes_pt.push_back(first_half_node_pt);
14327  output_sorted_nodes_pt.push_back(second_half_node_pt);
14328  // Add the sub-vector of elements to the vector of boundary
14329  // elements
14330  output_boundary_element_pt.push_back(first_half_ele_pt);
14331  output_boundary_element_pt.push_back(second_half_ele_pt);
14332  // Add the sub-vector of face elements to the vector of boundary
14333  // elements
14334  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14335  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14336  // Add the sub-vector of face indexes to the vector of face
14337  // indexes
14338  output_face_index_element.push_back(first_half_face_idx);
14339  output_face_index_element.push_back(second_half_face_idx);
14340 
14341  // Set the connection flags, change them by the proper connection
14342  // flag
14343 
14344  // ----------------------------------------------------------------
14345  // Connections flags for the first half
14346 
14347  // The left connection flag
14348 
14349  // Connected with nothing but required to stop adding nodes
14350  if (input_connect_to_the_left == -3)
14351  {
14352  // Set connected to nothing
14353  output_connect_to_the_left.push_back(-1);
14354  }
14355  // Connected with itself
14356  else if (input_connect_to_the_left == -2)
14357  {
14358  // Set connected to nothing, this is the base node
14359  output_connect_to_the_left.push_back(-1);
14360  }
14361  else
14362  {
14363  // Any other value keep it
14364  output_connect_to_the_left.push_back(input_connect_to_the_left);
14365  }
14366 
14367  // The right connection flag
14368 
14369  // Set connected to nothing, this is the base node
14370  output_connect_to_the_right.push_back(-1);
14371 
14372  // Increase the shared boundary id
14373  tmp_shd_bnd_id++;
14374 
14375  // ----------------------------------------------------------------
14376  // Connections flags for the second half
14377 
14378  // The left connection flag
14379 
14380  // Set connected to the previous boundary
14381  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
14382 
14383  // The right connection flag
14384 
14385  // Are we in the last sub-list of nodes, if that is the case we
14386  // need to respect the flag assigned to the right
14387  if (n_sub_list == 1)
14388  {
14389  if (input_connect_to_the_right == -3)
14390  {
14391  // Set connected to the previous shared boundary id
14392  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14393  }
14394  else if (input_connect_to_the_right == -2)
14395  {
14396  // Set connected to the previous shared boundary id
14397  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14398  }
14399  else if (input_connect_to_the_right == -1)
14400  {
14401  // Set connected to the previous shared boundary id
14402  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14403  }
14404  else
14405  {
14406  // Any other value keep it
14407  output_connect_to_the_right.push_back(input_connect_to_the_right);
14408  }
14409  } // if (n_sub_list == 1)
14410  else
14411  {
14412  // Set connected to the previous shared boundary id
14413  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14414  }
14415 
14416  // Increase the shared boundary id
14417  tmp_shd_bnd_id++;
14418 
14419  } // if (left_sub_node_pt == right_sub_node_pt)
14420 #ifdef PARANOID
14421  else
14422  {
14423  std::stringstream error_message;
14424  error_message
14425  << "The initial and final node in the current shared polyline are not\n"
14426  << "the same and the number of sublists is ("<< n_sub_list << ").\n"
14427  << "We can not handle more than one sublist in the method to break\n"
14428  << "loops at the load balance stage\n\n";
14429  throw OomphLibError(error_message.str(),
14430  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14431  OOMPH_EXCEPTION_LOCATION);
14432  }
14433 #endif
14434 
14435  }
14436 
14437  // ======================================================================
14438  // \short Create the shared polyline and fill the data structured
14439  // that keep all the information associated with the creationg of the
14440  // shared boundary
14441  // ======================================================================
14442  template<class ELEMENT>
14444  create_shared_polyline(const unsigned &my_rank,
14445  const unsigned &shd_bnd_id,
14446  const unsigned &iproc,
14447  const unsigned &jproc,
14448  std::list<Node*> &sorted_nodes,
14449  const int &root_edge_bnd_id,
14450  Vector<FiniteElement*> &bulk_bnd_ele_pt,
14451  Vector<int> &face_index_ele,
14452  Vector<Vector<TriangleMeshPolyLine *> >
14453  &unsorted_polylines_pt,
14454  const int &connect_to_the_left_flag,
14455  const int &connect_to_the_right_flag)
14456  {
14457  // ----------------------------------------------------------------
14458  // Associate the shared boundary with the respective processors
14459  // ----------------------------------------------------------------
14460 
14461  // Setup the global look-up scheme, where all processors know the
14462  // associations of others processors and the shared boundaries they
14463  // created
14464 
14465  // Set up the boundary shared by "iproc" with "jproc" processor
14466  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14467 
14468  // Set up the boundary shared by "jproc" with "iproc" processor
14469  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14470 
14471  // Specify the processors involved on the creation of the shared
14472  // boundary
14473  Vector<unsigned> processors(2);
14474  processors[0] = iproc;
14475  processors[1] = jproc;
14476  Shared_boundary_from_processors[shd_bnd_id] = processors;
14477 
14478  // ----------------------------------------------------------------
14479  // If one of the processor associated with the shared boundary is
14480  // the current processor then it needs to create a polyline from the
14481  // input sorted nodes, other processors can skip this part
14482  if (iproc == my_rank || jproc == my_rank)
14483  {
14484  // ------------------------------------------------------------
14485  // Create a vertices representation from the sorted nodes list
14486  // ------------------------------------------------------------
14487 
14488  // Get the number of nodes on the list
14489  const unsigned n_nodes = sorted_nodes.size();
14490  // The vector to store the vertices (assign space)
14491  Vector<Vector<double> > vertices(n_nodes);
14492 
14493  // Copy the vertices from the nodes
14494  unsigned counter = 0;
14495 
14496  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14497  it != sorted_nodes.end(); it++)
14498  {
14499  vertices[counter].resize(2);
14500  vertices[counter][0] = (*it)->x(0);
14501  vertices[counter][1] = (*it)->x(1);
14502  counter++;
14503  }
14504 
14505  // ---------------------------------------------
14506  // Create the polyline from the input vertices
14507  // ---------------------------------------------
14508  TriangleMeshPolyLine *polyline_pt =
14509  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14510 
14511  // ---------------------------------------------
14512  // Establish the internal boundary information
14513  // ---------------------------------------------
14514 
14515  // Check if the shared boundary is overlapping (or is part) of an
14516  // internal boundary
14517  if (root_edge_bnd_id != -1)
14518  {
14519  // If the shared boundary is part of an internal boundary then
14520  // mark the shared boundary
14521  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14522  static_cast<unsigned>(root_edge_bnd_id);
14523  } // if (root_edge_bnd_id != -1)
14524 
14525  // ---------------------------------------------
14526  // Store the boundary elements and face indexes
14527  // ---------------------------------------------
14528 
14529  // Store the shared boundary elements
14530  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14531 #ifdef PARANOID
14532  // Check that the number of shared boundy elements is the same as
14533  // the number of face indexes
14534  const unsigned n_face_index = face_index_ele.size();
14535  if (n_shared_boundary_elements != n_face_index)
14536  {
14537  std::ostringstream error_message;
14538  error_message
14539  << "The number of shared boundary elements is different from the\n"
14540  << "number of face indexes associated to the shared boundary\n"
14541  << "elements\n"
14542  << "Number of shared boundary elements: ("
14543  << n_shared_boundary_elements << ")\n"
14544  << "Number of face indexes: (" << n_face_index << ")\n\n";
14545  throw OomphLibError(error_message.str(),
14546  "TriangleMesh::create_shared_polyline()",
14547  OOMPH_EXCEPTION_LOCATION);
14548  } // if (n_shared_boundary_elements != n_face_index)
14549 #endif
14550 
14551  // Add the shared boundary elements and their respective face
14552  // indexes to their permanent containers
14553  for (unsigned i = 0 ; i < n_shared_boundary_elements; i++)
14554  {
14555  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14556  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14557  } // for (i < nshared_boundary_elements)
14558 
14559  // Store the shared boundary nodes
14560  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14561  it != sorted_nodes.end(); it++)
14562  {
14563  add_shared_boundary_node(shd_bnd_id, (*it));
14564  } // for (it != sorted_nodes.end())
14565 
14566  // ----------------------------------------------------------
14567  // Create additional look-up schemes for the shared boundary
14568  // ----------------------------------------------------------
14569 
14570  // Updates bnd_id <---> curve section map
14571  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14572 
14573  // Check the size of the unsorted_polylines_pt structure. This
14574  // will have n_procs = 1 when it was called from the
14575  // create_new_shared_boundaries() methods
14576  const unsigned n_procs = unsorted_polylines_pt.size();
14577  if (n_procs > 1)
14578  {
14579  // Add the new created polyline to the list of unsorted
14580  // polylines
14581  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14582 
14583  // ... do this on both processors involved in the creation of
14584  // the shared boundary
14585  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14586  }
14587  else
14588  {
14589  // Add the new created polyline to the list of unsorted
14590  // polylines
14591  unsorted_polylines_pt[0].push_back(polyline_pt);
14592  }
14593 
14594  // Mark the polyline for deletion (when calling destructor)
14595  this->Free_curve_section_pt.insert(polyline_pt);
14596 
14597  // ----------------------------
14598  // Set connection information
14599  // ----------------------------
14600 
14601  // Check that the flags are correct, no connection or the boundary
14602  // id of the boundary to connect
14603 #ifdef PARANOID
14604  // Is the shared polyline not connected to the left
14605  if (connect_to_the_left_flag < 0)
14606  {
14607  // If not connected then should be specified by -1
14608  if (connect_to_the_left_flag != -1)
14609  {
14610  std::ostringstream error_message;
14611  error_message
14612  << "The only accepted values for the connection flags are:\n"
14613  << "POSITIVE values or -1, any other value is rejected, please\n"
14614  << "check that you previously called the methods to deal with\n"
14615  << "other flag values\n"
14616  << "The current flag value for connection to the left is: ("
14617  << connect_to_the_left_flag<<")\n\n";
14618  throw OomphLibError(error_message.str(),
14619  "TriangleMesh::create_shared_polyline()",
14620  OOMPH_EXCEPTION_LOCATION);
14621  } // if (connect_to_the_left_flag != -1)
14622  } // if (connect_to_the_left_flag < 0)
14623 
14624  // Is the shared polyline not connected to the right
14625  if (connect_to_the_right_flag < 0)
14626  {
14627  // If not connected then should be specified by -1
14628  if (connect_to_the_right_flag != -1)
14629  {
14630  std::ostringstream error_message;
14631  error_message
14632  << "The only accepted values for the connection flags are:\n"
14633  << "POSITIVE values or -1, any other value is rejected, please\n"
14634  << "check that you previously called the methods to deal with\n"
14635  << "other flag values\n"
14636  << "The current flag value for connection to the right is: ("
14637  << connect_to_the_right_flag<<")\n\n";
14638  throw OomphLibError(error_message.str(),
14639  "TriangleMesh::create_shared_polyline()",
14640  OOMPH_EXCEPTION_LOCATION);
14641  } // if (connect_to_the_right_flag != -1)
14642  } // if (connect_to_the_right_flag < 0)
14643 #endif
14644 
14645  // Set the connection to the left
14646  if (connect_to_the_left_flag != -1)
14647  {
14648  // Get the unsigned version of the boundary id to the left
14649  const unsigned bnd_id_connection_to_the_left =
14650  static_cast<unsigned>(connect_to_the_left_flag);
14651  // Set the initial vertex as connected
14652  polyline_pt->set_initial_vertex_connected();
14653  // Set the initial vertex connected boundary id
14654  polyline_pt->initial_vertex_connected_bnd_id() =
14655  bnd_id_connection_to_the_left;
14656  // Set the chunk number to zero
14657  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14658 
14659  } // if (connect_to_the_left_flag != -1)
14660 
14661  // Set the connection to the right
14662  if (connect_to_the_right_flag != -1)
14663  {
14664  // Get the unsigned version of the boundary id to the right
14665  const unsigned bnd_id_connection_to_the_right =
14666  static_cast<unsigned>(connect_to_the_right_flag);
14667  // Set the final vertex as connected
14668  polyline_pt->set_final_vertex_connected();
14669  // Set the final vertex connected boundary id
14670  polyline_pt->final_vertex_connected_bnd_id() =
14671  bnd_id_connection_to_the_right;
14672  // Set the chunk number to zero
14673  polyline_pt->final_vertex_connected_n_chunk() = 0;
14674 
14675  } // if (connect_to_the_right_flag != -1)
14676 
14677  } // if (iproc == my_rank || jproc == my_rank)
14678 
14679  }
14680 
14681  //======================================================================
14682  /// \short Reset the boundary elements info. after load balance have
14683  /// taken place
14684  //======================================================================
14685  template <class ELEMENT>
14687  reset_boundary_element_info(Vector<unsigned> &ntmp_boundary_elements,
14688  Vector<Vector<unsigned> >
14689  &ntmp_boundary_elements_in_region,
14690  Vector<FiniteElement*> &deleted_elements)
14691  {
14692  // Get the number of boundaries
14693  const unsigned nbound = this->nboundary();
14694 
14695  // Are there regions?
14696  const unsigned n_regions = this->nregion();
14697 
14698  // Loop over the boundaries
14699  for (unsigned b = 0; b < nbound; b++)
14700  {
14701  // Get the boundary elements and back them up
14702  // -----------------------------------------------------------------
14703  // Get the number of boundary elements (mixed with the old and new)
14704  const unsigned nbound_ele = this->nboundary_element(b);
14705  // Back-up the boundary elements
14706  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14707  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14708  for (unsigned e = 0; e < nbound_ele; e++)
14709  {
14710  // Get the old boundary element
14711  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14712  // Get the old face index
14713  backed_up_face_index_at_boundary[e] =
14714  this->face_index_at_boundary(b, e);
14715  } // for (n < nold_boundary_elements)
14716 
14717  // Back up the elements in boundary for each region
14718  Vector<Vector<FiniteElement*> >
14719  backed_up_boundary_region_element_pt(n_regions);
14720  Vector<Vector<int> > backed_up_face_index_at_boundary_region(n_regions);
14721 
14722  // Loop over the regions and back up the boundary elements in
14723  // regions
14724  for (unsigned ir = 0; ir < n_regions; ir++)
14725  {
14726  // Get the region id
14727  const unsigned region_id =
14728  static_cast<unsigned>(this->region_attribute(ir));
14729  // Get the number of boundary region elements (mixed old and new)
14730  const unsigned nbnd_region_ele =
14731  this->nboundary_element_in_region(b, region_id);
14732 
14733  // Loop over the elements in the region
14734  for (unsigned e = 0; e < nbnd_region_ele; e++)
14735  {
14736  // Get the old boundary region element
14737  backed_up_boundary_region_element_pt[ir][e] =
14738  this->boundary_element_in_region_pt(b, region_id, e);
14739 
14740  // Get the old face index
14741  backed_up_face_index_at_boundary_region[ir][e] =
14742  this->face_index_at_boundary_in_region(b, region_id, e);
14743  } // for (e < nbnd_region_ele)
14744 
14745  } // for (ir < n_regions)
14746 
14747  // Clean all previous storages
14748  this->Boundary_element_pt[b].clear();
14749  this->Face_index_at_boundary[b].clear();
14750  if (n_regions > 0)
14751  {
14752  this->Boundary_region_element_pt[b].clear();
14753  this->Face_index_region_at_boundary[b].clear();
14754  }
14755 
14756  // -------------------------------------------------------------------
14757  // Now copy only the elements that are still alive, from those before
14758  // the re-establishment of halo and haloed elements
14759  // -------------------------------------------------------------------
14760  // Start with the boundary elements
14761  // Get the old number of boundary elements
14762  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14763  // Loop over the boundary elements and check those still alive
14764  for (unsigned e = 0; e < nold_bnd_ele; e++)
14765  {
14766  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14767  // Include only those elements still alive
14768  Vector<FiniteElement*>::iterator it =
14769  std::find(deleted_elements.begin(),
14770  deleted_elements.end(),
14771  tmp_ele_pt);
14772  // Only copy thoes elements not found on the deleted elements
14773  // container
14774  if (it == deleted_elements.end())
14775  {
14776  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14777  this->Boundary_element_pt[b].push_back(add_ele_pt);
14778  const int face_index = backed_up_face_index_at_boundary[e];
14779  this->Face_index_at_boundary[b].push_back(face_index);
14780  } // if (tmp_ele_pt != 0)
14781 
14782  } // for (n < nold_bnd_ele)
14783 
14784  // ... continue with the boundary elements in specific regions
14785 
14786  // Loop over the regions
14787  for (unsigned ir = 0; ir < n_regions; ir++)
14788  {
14789  // Get the region id
14790  const unsigned region_id =
14791  static_cast<unsigned>(this->region_attribute(ir));
14792 
14793  // Get the old number of boundary elements in region
14794  const unsigned nold_bnd_region_ele =
14795  ntmp_boundary_elements_in_region[b][ir];
14796 
14797  // Loop over the boundary region elements and check those still
14798  // alive
14799  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14800  {
14801  // Get the element
14802  FiniteElement* tmp_ele_pt =
14803  backed_up_boundary_region_element_pt[ir][e];
14804  // Include only those elements still alive
14805  Vector<FiniteElement*>::iterator it =
14806  std::find(deleted_elements.begin(),
14807  deleted_elements.end(),
14808  tmp_ele_pt);
14809  // Only copy those elements not found on the deleted elements
14810  // container
14811  if (it == deleted_elements.end())
14812  {
14813  FiniteElement* add_ele_pt =
14814  backed_up_boundary_region_element_pt[ir][e];
14815  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14816  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14817  this->Face_index_region_at_boundary[b][region_id].
14818  push_back(face_index);
14819  } // if (tmp_ele_pt != 0)
14820 
14821  } // for (n < nbound_ele)
14822 
14823  } // for (ir < n_regions)
14824 
14825  // ----------------------------------------------------------------
14826  // Now copy all those elements created after the re-establishment
14827  // of halo and haloed elements
14828  // ----------------------------------------------------------------
14829  // Loop over the boundary elements
14830  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
14831  {
14832  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14833  this->Boundary_element_pt[b].push_back(add_ele_pt);
14834  const int face_index = backed_up_face_index_at_boundary[e];
14835  this->Face_index_at_boundary[b].push_back(face_index);
14836  } // for (e < nbound_ele)
14837 
14838  // Now add the boundary elements in regions
14839 
14840  // Loop over the regions
14841  for (unsigned ir = 0; ir < n_regions; ir++)
14842  {
14843  // Get the region id
14844  const unsigned region_id =
14845  static_cast<unsigned>(this->region_attribute(ir));
14846 
14847  // Get the old number of boundary elements in region
14848  const unsigned nold_bnd_region_ele =
14849  ntmp_boundary_elements_in_region[b][ir];
14850 
14851  // Get the new number of boundary elements in region
14852  const unsigned nbnd_region_ele =
14853  this->nboundary_element_in_region(b, region_id);
14854 
14855  // Loop over the boundary region elements and check those still
14856  // alive
14857  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
14858  {
14859  FiniteElement* add_ele_pt = backed_up_boundary_region_element_pt[ir][e];
14860  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14861  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14862  this->Face_index_region_at_boundary[b][region_id].push_back(face_index);
14863  } // for (e < nbnd_region_ele)
14864 
14865  } // for (ir < n_regions)
14866 
14867  } // for (b < nbound)
14868 
14869  // Lookup scheme has now been setup yet
14870  Lookup_for_elements_next_boundary_is_setup=true;
14871 
14872  }
14873 
14874 #endif // OOMPH_HAS_MPI
14875 
14876 #ifdef OOMPH_HAS_TRIANGLE_LIB
14877 
14878 //========================================================================
14879 /// Build a new TriangulateIO object based on target areas specified
14880 //========================================================================
14881 template <class ELEMENT>
14883  TriangulateIO& triangulate_io,
14884  const Vector<double>& target_area,
14885  struct TriangulateIO& triangle_refine)
14886  {
14887 
14888  // Initialize
14889  TriangleHelper::initialise_triangulateio(triangle_refine);
14890 
14891  // Store the global number of vertices and segments
14892  // in the list
14893  unsigned n_points = triangulate_io.numberofpoints;
14894  triangle_refine.numberofpoints=n_points;
14895 
14896  unsigned n_segments=triangulate_io.numberofsegments;
14897  triangle_refine.numberofsegments=n_segments;
14898 
14899  // Initialization of the TriangulateIO objects to store the values
14900  triangle_refine.pointlist =
14901  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
14902  triangle_refine.pointmarkerlist =
14903  (int *) malloc(triangulate_io.numberofpoints * sizeof(int));
14904  triangle_refine.segmentlist =
14905  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
14906  triangle_refine.segmentmarkerlist =
14907  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
14908 
14909  // Storing the point's coordinates in the list
14910  // and in two vectors with x and y coordinates
14911  Vector<double> x_coord (n_points);
14912  Vector<double> y_coord (n_points);
14913 
14914  for(unsigned count_point=0;count_point<n_points*2;count_point++)
14915  {
14916  triangle_refine.pointlist[count_point]=
14917  triangulate_io.pointlist[count_point];
14918 
14919  // Even vaules represent the x coordinate
14920  // Odd values represent the y coordinate
14921  if (count_point%2==0)
14922  {
14923  x_coord[count_point/2] = triangulate_io.pointlist[count_point];
14924  }
14925  else
14926  {
14927  y_coord[(count_point-1)/2] = triangulate_io.pointlist[count_point];
14928  }
14929  }
14930 
14931  // Store the point's markers in the list
14932  for(unsigned count_marker=0;count_marker<n_points;count_marker++)
14933  {
14934  triangle_refine.pointmarkerlist[count_marker]=
14935  triangulate_io.pointmarkerlist[count_marker];
14936  }
14937 
14938  // Storing the segment's edges in the list
14939  for(unsigned count_seg=0;count_seg<n_segments*2;count_seg++)
14940  {
14941  triangle_refine.segmentlist[count_seg]=
14942  triangulate_io.segmentlist[count_seg];
14943  }
14944 
14945  // Store the segment's markers in the list
14946  for(unsigned count_markers=0;count_markers<n_segments;count_markers++)
14947  {
14948  triangle_refine.segmentmarkerlist[count_markers]=
14949  triangulate_io.segmentmarkerlist[count_markers];
14950  }
14951 
14952  // Store the hole's center coordinates
14953  unsigned n_holes = triangulate_io.numberofholes;
14954  triangle_refine.numberofholes = n_holes;
14955 
14956  triangle_refine.holelist =
14957  (double*) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
14958 
14959  // Loop over the holes to get centre coords
14960  for(unsigned count_hole=0;count_hole<n_holes*2;count_hole++)
14961  {
14962  triangle_refine.holelist[count_hole] = triangulate_io.holelist[count_hole];
14963  }
14964 
14965  // Store the triangles values
14966  unsigned n_triangles = triangulate_io.numberoftriangles;
14967  triangle_refine.numberoftriangles = n_triangles;
14968 
14969 #ifdef PARANOID
14970  if (n_triangles!=target_area.size())
14971  {
14972  std::stringstream err;
14973  err << "Number of triangles in triangulate_io="
14974  << n_triangles << " doesn't match\n"
14975  << "size of target area vector ("
14976  << target_area.size() << ")\n";
14977  throw OomphLibError(
14978  err.str(),
14979  OOMPH_CURRENT_FUNCTION,
14980  OOMPH_EXCEPTION_LOCATION);
14981  }
14982 #endif
14983 
14984  unsigned n_corners = triangulate_io.numberofcorners;
14985  triangle_refine.numberofcorners = n_corners;
14986 
14987  triangle_refine.trianglelist =
14988  (int *) malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
14989 
14990  // Store the triangle's corners in the list and get element sizes
14991  for(unsigned count_tri=0;count_tri<n_triangles*3;count_tri++)
14992  {
14993  triangle_refine.trianglelist[count_tri]=
14994  triangulate_io.trianglelist[count_tri];
14995  }
14996 
14997  // Store the triangle's area in the list
14998  triangle_refine.trianglearealist =
14999  (double *) malloc(triangulate_io.numberoftriangles * sizeof(double));
15000  for(unsigned count_area=0;count_area<n_triangles;count_area++)
15001  {
15002  triangle_refine.trianglearealist[count_area]=target_area[count_area];
15003  }
15004 
15005  // Store the triangles attributes in the list
15006  triangle_refine.numberoftriangleattributes =
15007  triangulate_io.numberoftriangleattributes;
15008 
15009  triangle_refine.triangleattributelist =
15010  (double *) malloc(
15011  triangulate_io.numberoftriangles *
15012  triangulate_io.numberoftriangleattributes * sizeof(double));
15013  for(unsigned count_attribute=0;
15014  count_attribute<(n_triangles*triangulate_io.numberoftriangleattributes);
15015  count_attribute++)
15016  {
15017  triangle_refine.triangleattributelist[count_attribute] =
15018  triangulate_io.triangleattributelist[count_attribute];
15019  }
15020 
15021  }
15022 
15023 #ifdef OOMPH_HAS_MPI
15024 
15025  // ===================================================================
15026  // The comparison class for the map that sorts the nodes on the
15027  // shared boundary (using a lexicographic order)
15028  // ===================================================================
15029  struct classcomp
15030  {
15031 
15032  // Tolerance for lower-left comparison
15033  static double Tol;
15034 
15035 
15036  // Comparison operator for "lower left" ordering
15037  bool operator() (const std::pair<double, double> &lhs,
15038  const std::pair<double, double> &rhs) const
15039  {
15040  double diff_y=lhs.second-rhs.second;
15041  if (diff_y<-Tol) // (lhs.second < rhs.second)
15042  {
15043  return true;
15044  }
15045  else
15046  {
15047  // Are they "equal" with 1.0e-14 tolerance?
15048  if (diff_y<Tol) // (lhs.second == rhs.second)
15049  {
15050 #ifdef PARANOID
15051  double diff_x=lhs.first-rhs.first;
15052  if (fabs(diff_x)<Tol)
15053  {
15054  std::ostringstream warning_message;
15055  warning_message
15056  << "Dodgy \"lower left\" (lexicographic) comparison "
15057  << "of points with cooordinates: "
15058  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15059  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15060  << "x and y coordinates differ by less than tolerance!\n"
15061  << "diff_x = " << diff_x << "\n"
15062  << "diff_y = " << diff_y << "\n"
15063  << "Tol = " << Tol << "\n";
15064  OomphLibError(warning_message.str(),
15065  OOMPH_CURRENT_FUNCTION,
15066  OOMPH_EXCEPTION_LOCATION);
15067  }
15068 #endif
15069  if (lhs.first < rhs.first)
15070  {
15071  return true;
15072  }
15073  else
15074  {
15075  return false;
15076  }
15077  }
15078  else
15079  {
15080  return false;
15081  }
15082  }
15083 
15084 
15085 
15086  // if (lhs.second < rhs.second)
15087  // {
15088  // return true;
15089  // }
15090  // else
15091  // {
15092  // // // Are "equal" with 1.0e-14 tolerance
15093  // // if (lhs.second - rhs.second < 1.0e-14)
15094  // // Are equal?
15095  // if (lhs.second == rhs.second)
15096  // {
15097  // if (lhs.first < rhs.first)
15098  // {
15099  // return true;
15100  // }
15101  // else
15102  // {
15103  // return false;
15104  // }
15105  // }
15106  // else
15107  // {
15108  // return false;
15109  // }
15110  // }
15111 
15112 
15113  }
15114 
15115  } Bottom_left_sorter; // struct classcomp
15116 
15117 
15118  // Assign value for tolerance
15119  double classcomp::Tol=1.0e-14;
15120 
15121 
15122  //======================================================================
15123  // Sort the nodes on shared boundaries so that the processors that share
15124  // a boundary agree with the order of the nodes on the boundary
15125  //======================================================================
15126  template <class ELEMENT>
15128  {
15129  // Get the shared boundaries in this processor
15130  Vector<unsigned> my_rank_shared_boundaries_ids;
15131  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15132 
15133  // Get the number of shared boundaries
15134  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15135 
15136  // Loop over the shared boundaries
15137  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15138  {
15139  // A map is used to sort the nodes using their coordinates as the key
15140  // of the map
15141  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15142  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15143 
15144 
15145 #ifdef PARANOID
15146 
15147  // Check min distance between nodes; had better be less than the
15148  // tolerance used for the bottom left sorting
15149  double min_distance_squared=DBL_MAX;
15150 
15151 #endif
15152 
15153  // Get the boundary id
15154  const unsigned b = my_rank_shared_boundaries_ids[i];
15155 
15156  // Get the number of nodes on the current boundary
15157  const unsigned nbnd_node = this->nshared_boundary_node(b);
15158 
15159  // Go through all the nodes on the boundary and temporarily store
15160  // them on the map container
15161  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15162  {
15163  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15164  std::pair<double, double> vertex = std::make_pair(node_pt->x(0),
15165  node_pt->x(1));
15166  sorted_nodes_pt[vertex] = node_pt;
15167 
15168 
15169 
15170 #ifdef PARANOID
15171 
15172  // Check for minimum distance
15173  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15174  {
15175  if (i_node!=j_node)
15176  {
15177  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15178 
15179  // Squared distance
15180  double squared_distance=0.0;
15181  for (unsigned ii=0;ii<2;ii++)
15182  {
15183  squared_distance+=
15184  (node_pt->x(ii)-node2_pt->x(ii))*
15185  (node_pt->x(ii)-node2_pt->x(ii));
15186  }
15187  if (squared_distance<min_distance_squared)
15188  {
15189  min_distance_squared=squared_distance;
15190  }
15191  }
15192  }
15193 
15194  if (sqrt(min_distance_squared)<Bottom_left_sorter.Tol)
15195  {
15196  std::ostringstream warning_message;
15197  warning_message
15198  << "Minimum distance between nodes on boundary " << b << "\n"
15199  << "is " << sqrt(min_distance_squared) << " which is less than "
15200  << "Bottom_left_sorter.Tol = " << Bottom_left_sorter.Tol << "\n"
15201  << "This may screw up the ordering of the nodes on shared boundaries\n";
15202  OomphLibWarning(warning_message.str(),
15203  OOMPH_CURRENT_FUNCTION,
15204  OOMPH_EXCEPTION_LOCATION);
15205  }
15206 
15207 #endif
15208 
15209  }
15210 
15211  unsigned counter = 0;
15212  // Resize the sorted shared boundary node vector
15213  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15214 
15215  // Now go through the map container, get the elements and store their
15216  // members on the Sorted_shared_boundary_node_pt container
15217  // The map has already sorted the nodes, now they keep the same sorting
15218  // on all processors
15219  for (std::map<std::pair<double, double>, Node*>::iterator it_map
15220  = sorted_nodes_pt.begin(); it_map != sorted_nodes_pt.end(); it_map++)
15221  {
15222  // Store the pointer to the node
15223  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15224  }
15225 
15226  } // for (i < nmy_rank_shd_bnd)
15227 
15228  }
15229 
15230  //========================================================================
15231  // Re-establish the shared boundary elements after the adaptation
15232  // process (the updating of shared nodes is optional and performed by
15233  // default)
15234  //========================================================================
15235  template <class ELEMENT>
15238  const bool update_elements,
15239  const bool flush_nodes,
15240  const bool update_nodes)
15241  {
15242  // Get the rank of the current processor
15243  const unsigned my_rank = this->communicator_pt()->my_rank();
15244 
15245  // Go through the boundaries know as shared boundaries and copy the
15246  // elements to the corresponding storage
15247 
15248  // Get the initial shared boundary id
15249  const unsigned initial_id = this->initial_shared_boundary_id();
15250 
15251  // Get the final shared boundary id
15252  const unsigned final_id = this->final_shared_boundary_id();
15253 
15254  if (flush_elements)
15255  {
15256  // Flush the shared boundaries storage for elements
15257  this->flush_shared_boundary_element();
15258  // .. and also flush the face indexes associated with the element
15259  this->flush_face_index_at_shared_boundary();
15260  } // if (flush_elements)
15261 
15262  if (flush_nodes)
15263  {
15264  // Flush the shared boundaries storage for nodes
15265  this->flush_shared_boundary_node();
15266  } // if (flush_nodes)
15267 
15268  for (unsigned b = initial_id; b < final_id; b++)
15269  {
15270  // Check if the boundary is on the current processor
15271  Vector<unsigned> procs_from_shrd_bnd;
15272  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15273  bool current_processor_has_b_boundary = false;
15274  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15275  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15276  {
15277  if (procs_from_shrd_bnd[p] == my_rank)
15278  {
15279  current_processor_has_b_boundary = true;
15280  break; // break for (p < n_procs_from_shrd_bnd)
15281  }
15282  } // for (p < n_procs_from_shrd_bnd)
15283 
15284  if (current_processor_has_b_boundary)
15285  {
15286  if (update_elements)
15287  {
15288  const unsigned nboundary_ele = this->nboundary_element(b);
15289  for (unsigned e = 0; e < nboundary_ele; e++)
15290  {
15291  // Get the boundary element and add it to the shared
15292  // boundary elements structure
15293  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15294  this->add_shared_boundary_element(b, bnd_ele_pt);
15295  // ... do the same with the face index information
15296  int face_index = this->face_index_at_boundary(b, e);
15297  this->add_face_index_at_shared_boundary(b, face_index);
15298  } // for (e < nboundary_element)
15299  } // if (update_elements)
15300 
15301  if (update_nodes)
15302  {
15303 
15304 
15305  const unsigned nboundary_node = this->nboundary_node(b);
15306  for (unsigned n = 0; n < nboundary_node; n++)
15307  {
15308  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15309  this->add_shared_boundary_node(b, bnd_node_pt);
15310  } // for (n < nboundary_node)
15311  } // if (update_nodes)
15312 
15313  } // if (current_processor_has_b_boundary)
15314  } // for (b < final_id)
15315 
15316  }
15317 
15318  //======================================================================
15319  // Sort the nodes on shared boundaries so that the processors that share
15320  // a boundary agree with the order of the nodes on the boundary
15321  //======================================================================
15322  template <class ELEMENT>
15324  {
15325  // Get the number of processors
15326  unsigned nproc = this->communicator_pt()->nproc();
15327  // Get the rank of the current processor
15328  unsigned my_rank = this->communicator_pt()->my_rank();
15329 
15330  // Get some timings
15331  double tt_start = 0.0;
15332  double tt_end=0.0;
15333  if (Global_timings::Doc_comprehensive_timings)
15334  {
15335  tt_start=TimingHelpers::timer();
15336  }
15337 
15338  // -------------------------------------------------------------------
15339  // BEGIN: Get the node names and the shared nodes
15340  // -------------------------------------------------------------------
15341 
15342  // Container where to store the nodes on shared boundaries no
15343  // associated with the processor that receives the elements/nodes
15344  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15345  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15346  other_proc_shd_bnd_node_pt(nproc);
15347  // Resize the container
15348  for (unsigned iproc = 0; iproc < nproc; iproc++)
15349  {
15350  // Resize the container
15351  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15352  for (unsigned jproc = 0; jproc < nproc; jproc++)
15353  {
15354  // Get the number of shared boundaries
15355  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15356  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15357  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15358  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15359  } // for (jproc < nproc)
15360 
15361  } // for (iproc < nproc)
15362 
15363  // Store the global node names
15364  // global_node_name[x][ ][ ] Global node number
15365  // global_node_name[ ][x][ ] Global node names
15366  // global_node_name[ ][ ][x] Global node info.
15367  Vector<Vector<Vector<unsigned> > > global_node_names;
15368 
15369  // Creates a map between the node name and the index of the global
15370  // node so we can access all its node names
15371  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15372 
15373  // Store the global shared nodes pointers
15374  Vector<Node*> global_shared_node_pt;
15375 
15376  // Get the time for computation of global nodes names and shared
15377  // nodes
15378  double t_start_global_node_names_and_shared_nodes =
15379  TimingHelpers::timer();
15380 
15381  // Compute all the names of the nodes and fill in the
15382  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15383  // on this processor (my_rank) by looking over all their names
15384  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15385  global_node_names,
15386  node_name_to_global_index,
15387  global_shared_node_pt);
15388 
15389  // Compute the number of elements before adding new ones
15390  const unsigned n_ele = this->nelement();
15391 
15392  if (Print_timings_level_adaptation>1)
15393  {
15394  // The total time for computation of global nodes names and
15395  // shared nodes
15396  double t_final_global_node_names_and_shared_nodes =
15397  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15398  oomph_info << "CPU for computing global node names and shared nodes "
15399  << "[n_ele="<< n_ele << "]: "
15400  << t_final_global_node_names_and_shared_nodes << std::endl;
15401  }
15402 
15403  // -------------------------------------------------------------------
15404  // END: Get the node names and the shared nodes
15405  // -------------------------------------------------------------------
15406 
15407  // -------------------------------------------------------------------
15408  // BEGIN: Using the global node names each processor sends info. of
15409  // the nodes shared with other processors regarding whether they are
15410  // on an original boundary or not. This is required so that at the
15411  // re-generation of halo(ed) elements stage they have the updated
15412  // information
15413  // -------------------------------------------------------------------
15414 
15415  // Get the time for sending info. of shared nodes on original
15416  // boundaries
15417  double t_start_send_info_shd_nodes_on_original_bnds =
15418  TimingHelpers::timer();
15419 
15420  // Send the boundary node info. of nodes on shared boundaries across
15421  // processors
15422  send_boundary_node_info_of_shared_nodes(global_node_names,
15423  node_name_to_global_index,
15424  global_shared_node_pt);
15425 
15426  if (Print_timings_level_adaptation>1)
15427  {
15428  // The total time for sending info. of shared nodes lying on
15429  // original boundaries
15430  oomph_info
15431  <<"CPU for sending info. of shared nodes on original boundaries: "
15432  <<TimingHelpers::timer()-t_start_send_info_shd_nodes_on_original_bnds
15433  <<std::endl;
15434  }
15435 
15436  // -------------------------------------------------------------------
15437  // END: Using the global node names each processor sends info. of
15438  // the nodes shared with other processors regarding whether they are
15439  // on an original boundary or not. This is required so that at the
15440  // re-generation of halo(ed) elements stage they have the updated
15441  // information
15442  // -------------------------------------------------------------------
15443 
15444  // -------------------------------------------------------------------
15445  // BEGIN: Identify the elements of the mesh that have nodes on the
15446  // shared boundaries
15447  // -------------------------------------------------------------------
15448 
15449  // Store the elements that have a node on a shared boundary with
15450  // other processors
15451  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15452  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15453  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15454  // boundary with iproc
15455  Vector<Vector<Vector<FiniteElement*> > > ele_with_node_on_shd_bnd_pt(nproc);
15456  // Resize the container with the number of shared boundaries within
15457  // each processor
15458 
15459  // loop over the processors
15460  for (unsigned iproc = 0; iproc < nproc; iproc++)
15461  {
15462  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15463  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15464  } // for (iproc < nproc)
15465 
15466  // Go through all the elements and check whether any of their nodes
15467  // lies on any of the shared boundaries
15468 
15469  // loop over the elements
15470  for (unsigned e = 0; e < n_ele; e++)
15471  {
15472  // Get the element
15473  FiniteElement* ele_pt = this->finite_element_pt(e);
15474  // Get the number of nodes
15475  const unsigned n_nodes = ele_pt->nnode();
15476  // loop over the nodes and check whether any of them lies on a
15477  // shared boundary
15478  for (unsigned n = 0; n < n_nodes; n++)
15479  {
15480  // Get the node
15481  Node* node_pt = ele_pt->node_pt(n);
15482 
15483  // Now check whether the current node lies on a shared boundary
15484  // within any other processor
15485 
15486  // loop over the processors
15487  for (unsigned iproc = 0; iproc < nproc; iproc++)
15488  {
15489  // The number of boundaries shared with the current processor
15490  // (if iproc==my_rank then there are no shared boundaries
15491  // between them)
15492  const unsigned n_shd_bnd_iproc =
15493  this->nshared_boundaries(my_rank, iproc);
15494 
15495  // There are no info. with myself
15496  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15497  {
15498  // Get the boundaries ids of the shared boundaries with
15499  // iproc processor
15500  Vector<unsigned> shd_bnd_ids =
15501  this->shared_boundaries_ids(my_rank, iproc);
15502 
15503  // Loop over shd bnds with processor "iproc"
15504  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15505  {
15506  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15507  const unsigned n_ele_shd_bnd =
15508  this->nshared_boundary_element(shd_bnd_id);
15509 
15510  // Check if the node is on this boundary only if there are
15511  // elements on it
15512  if (n_ele_shd_bnd > 0 &&
15513  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15514  {
15515  // Add the element into those that have a
15516  // node on the current shared boundary
15517  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15518 
15519  } // Are there elements on the boundary and the node lies
15520  // on this boundary
15521 
15522  } // for (isb < n_shd_bnd_iproc)
15523 
15524  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15525 
15526  } // for (iproc < nproc)
15527 
15528  } // for (n < n_nodes)
15529 
15530  } // for (e < n_ele)
15531 
15532  // -------------------------------------------------------------------
15533  // END: Identify the elements of the mesh that have nodes on the
15534  // shared boundaries
15535  // -------------------------------------------------------------------
15536 
15537  // -------------------------------------------------------------------
15538  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15539  // the shared boundaries within each processor. Get the elements on
15540  // the shared boundaries, mark them as haloed in this processor and
15541  // as halo on the element that will receive the info.
15542  // -------------------------------------------------------------------
15543 
15544  // ********************************************************************
15545  // General strategy:
15546  // 1) Go through all the elements on the shared boundaries, mark these
15547  // elements as haloed, same as their nodes.
15548  // 2) Package the info. of the nodes and the elements.
15549  // 3) Send and receive the info across processors
15550  // 4) Unpackage it and create halo elements and nodes as indicated by
15551  // the received info.
15552  // ********************************************************************
15553 
15554  // Keep track of the currently created nodes within each
15555  // processor. We need to keep track of these nodes so they can be
15556  // referred at a second stage.
15557  Vector<Vector<Node*> > iproc_currently_created_nodes_pt(nproc);
15558 
15559  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15560  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15561  TimingHelpers::timer();
15562 
15563  // Go through all processors
15564  for (unsigned iproc = 0; iproc < nproc; iproc++)
15565  {
15566  // Send and receive info. to/from other processors
15567  if (iproc != my_rank)
15568  {
15569  // Get the number of boundaries shared with the send proc (iproc)
15570  const unsigned nshared_boundaries_with_iproc =
15571  this->nshared_boundaries(my_rank, iproc);
15572 
15573  if (nshared_boundaries_with_iproc > 0)
15574  {
15575  // ******************************************************************
15576  // Stage 1
15577  // ******************************************************************
15578  // Step (1) Mark the elements adjacent to the shared boundaries as
15579  // haloed, mark the nodes on these elements as haloed nodes
15580  // Step (2) Create packages of information indicating the generation
15581  // of halo elements and nodes
15582  // ******************************************************************
15583 
15584  // Clean send and receive buffers
15585  Flat_packed_unsigneds.clear();
15586  Flat_packed_doubles.clear();
15587 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15588  Flat_packed_unsigneds_string.clear();
15589 #endif
15590 
15591  // Get the boundaries ids shared with "iproc"
15592  Vector<unsigned> bound_shared_with_iproc;
15593  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15594 
15595  // Loop over shared boundaries with processor "iproc"
15596  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15597  {
15598  const unsigned bnd_id = bound_shared_with_iproc[bs];
15599 // DEBP(bnd_id);
15600  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15601 // DEBP(nel_bnd);
15602 
15603  // Container to store the elements marked as haloed
15604  Vector<FiniteElement*> haloed_element;
15605 
15606  // All the elements adjacent to the boundary should be
15607  // marked as haloed elements
15608  if (nel_bnd > 0)
15609  {
15610  // Map to know which element have been already added
15611  std::map<FiniteElement*,bool> already_added;
15612 
15613  // Loop over the elements adjacent to boundary "bnd_id"
15614  for (unsigned e = 0; e < nel_bnd; e++)
15615  {
15616  // Get pointer to the element adjacent to boundary bnd_id
15617  FiniteElement* ele_pt =
15618  this->shared_boundary_element_pt(bnd_id, e);
15619 
15620  // Check if the element has been already added. Elemets
15621  // are repeated if they have two faces on the shared
15622  // boundary
15623  if (!already_added[ele_pt])
15624  {
15625  // Add the element to the container of haloed elements
15626  haloed_element.push_back(ele_pt);
15627  // Mark the element as already added
15628  already_added[ele_pt] = true;
15629  }
15630 
15631  } // for (e < nel_bnd)
15632 
15633  // In addition to the elements on the boundary we also
15634  // need to mark (as haloed) any element on the mesh with a
15635  // node on the shared boundary
15636 
15637  // Get the number of elements with a node on the current
15638  // shared boundary
15639  const unsigned n_ele_with_node_on_shd_bnd =
15640  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15641  // loop and add the elements that have a node on the
15642  // current shared boundary with the current processor
15643  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15644  {
15645  // Get the element
15646  FiniteElement* ele_pt =
15647  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15648  // Check if it has not been already added
15649  if (!already_added[ele_pt])
15650  {
15651  // Add it!!
15652  haloed_element.push_back(ele_pt);
15653  // Mark it as done
15654  already_added[ele_pt] = true;
15655  } // if (!already_added[ele_pt])
15656 
15657  } // for (iele < n_ele_with_node_on_shd_bnd)
15658 
15659  } // if (nel_bnd > 0)
15660 
15661  // Get the total number of haloed elements
15662  const unsigned nhaloed_ele = haloed_element.size();
15663  // DEBP(nhaloed_ele);
15664  // DEBP(my_rank);
15665  // DEBP(iproc);
15666  // The very first data of the flat packed is the number of haloed
15667  // elements, this will be the number of halo element to create on
15668  // the receiver processor
15669  Flat_packed_unsigneds.push_back(nhaloed_ele);
15670 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15671  std::stringstream junk;
15672  junk << "Number of haloed elements " << nhaloed_ele;
15673  Flat_packed_unsigneds_string.push_back(junk.str());
15674 #endif
15675 
15676  // Loop over the marked haloed elements
15677  for (unsigned e = 0; e < nhaloed_ele; e++)
15678  {
15679  // Get pointer to the marked haloed element
15680  FiniteElement* ele_pt = haloed_element[e];
15681  const unsigned nroot_haloed_ele =
15682  this->nroot_haloed_element(iproc);
15683 
15684  // Check if the element has been already added to the
15685  // halo(ed) scheme
15686  GeneralisedElement *gen_ele_pt = ele_pt;
15687  const unsigned haloed_ele_index =
15688  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15689 
15690  // Was the element added or only returned the index of the
15691  // element
15692  if (nroot_haloed_ele == haloed_ele_index)
15693  {
15694  Flat_packed_unsigneds.push_back(1);
15695 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15696  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
15697 #endif
15698 
15699  // Get additional info. related with the haloed element
15700  get_required_elemental_information_helper(iproc, ele_pt);
15701 
15702  // Get the nodes on the element
15703  const unsigned nnodes = ele_pt->nnode();
15704  for (unsigned j = 0; j < nnodes; j++)
15705  {
15706  Node* node_pt = ele_pt->node_pt(j);
15707 
15708  // Package the info. of the nodes
15709  // The destination processor goes in the arguments
15710  add_haloed_node_helper(iproc, node_pt);
15711 
15712  } // for (j < nnodes)
15713  } // add the element and send its nodes
15714  else // The haloed element already exists
15715  {
15716  Flat_packed_unsigneds.push_back(0);
15717 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15718  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
15719 #endif
15720  Flat_packed_unsigneds.push_back(haloed_ele_index);
15721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15722  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
15723 #endif
15724  } // else (next_haloed_ele == external_haloed_ele_index)
15725  } // for (e < nel_bnd)
15726 
15727  } // for (bs < nshared_boundaries_with_iproc)
15728 
15729  // *******************************************************************
15730  // Stage (2)
15731  // *******************************************************************
15732  // Step (1) Send and receive the data to create halo elements and
15733  // nodes
15734  // *******************************************************************
15735  // The processor to which send the elements
15736  int send_proc = static_cast<int>(iproc);
15737  // The processor from which receive the elements
15738  int recv_proc = static_cast<int>(iproc);
15739  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15740 
15741  // *******************************************************************
15742  // Stage (3)
15743  // *******************************************************************
15744  // Step (1) Unpackage the info and create the halo elements and nodes
15745  // *******************************************************************
15746 
15747  // Reset the counters
15748  Counter_for_flat_packed_doubles=0;
15749  Counter_for_flat_packed_unsigneds=0;
15750 
15751  // Loop over shared boundaries with processor "iproc"
15752  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15753  {
15754  // Get the number of halo element to be created
15755  const unsigned nhaloed_ele =
15756  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
15757 
15758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15759  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
15760  << " Number of elements need to be constructed "
15761  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
15762  << std::endl;
15763 #endif
15764 
15765  // Loop over boundaries shared with processor "urecv_proc"
15766  for (unsigned e = 0; e < nhaloed_ele; e++)
15767  {
15768  // Create halo element from received info. of "iproc"
15769  // processor on the current processor
15770  create_halo_element(iproc,
15771  iproc_currently_created_nodes_pt[iproc],
15772  other_proc_shd_bnd_node_pt,
15773  global_node_names,
15774  node_name_to_global_index,
15775  global_shared_node_pt);
15776 
15777  } // for (e < nhaloed_ele)
15778 
15779  } // for (bs < nshared_boundaries_with_iproc)
15780 
15781  } // if (nshared_bound_recv_proc > 0)
15782 
15783  } // if (iproc != my_rank)
15784 
15785  } // for (iproc < nproc) (general loop to send and receive info.)
15786 
15787  if (Print_timings_level_adaptation>1)
15788  {
15789  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15790  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15791  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_first_stage;
15792 
15793  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15794  << "(first stage) [n_ele="<< n_ele << "]: "
15795  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15796  << std::endl;
15797  }
15798 
15799  // -------------------------------------------------------------------
15800  // END: Create the halo(ed) elements. Loop over the processors and
15801  // the shared boundaries within each processor. Get the elements on
15802  // the shared boundaries, mark them as haloed in this processor and
15803  // as halo on the element that will receive the info.
15804  // -------------------------------------------------------------------
15805 
15806  // -------------------------------------------------------------------
15807  // BEGIN: Create any additional haloed element, those that dont lie
15808  // on a shared boundary but that shared a node with other processor
15809  // -------------------------------------------------------------------
15810 
15811  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15812  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15813  TimingHelpers::timer();
15814 
15815  // Create any additional halo(ed) elements between processors that
15816  // have no shared boundaries but that have shared nodes
15817  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15818  iproc_currently_created_nodes_pt,
15819  global_node_names,
15820  node_name_to_global_index,
15821  global_shared_node_pt);
15822 
15823  if (Print_timings_level_adaptation>1)
15824  {
15825  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15826  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15827  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_second_stage;
15828 
15829  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15830  << "(second stage) [n_ele="<< n_ele << "]: "
15831  << t_final_regenerate_halo_ed_elements_nodes_second_stage
15832  << std::endl;
15833  }
15834 
15835  // -------------------------------------------------------------------
15836  // END: Create any additional haloed element, those that dont lie on
15837  // a shared boundary but that shared a node with other processor
15838  // -------------------------------------------------------------------
15839 
15840  // Clean send and receive buffers
15841  Flat_packed_unsigneds.clear();
15842  Flat_packed_doubles.clear();
15843 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15844  Flat_packed_unsigneds_string.clear();
15845 #endif
15846 
15847  // Document the timings for reseting halo and haloed scheme (without
15848  // classification of halo and haloed nodes)
15849  if (Print_timings_level_adaptation>1)
15850  {
15851  tt_end = TimingHelpers::timer();
15852  oomph_info
15853  << "CPU for resetting halo-haloed scheme (without classification of halo and haloed nodes): "
15854  << tt_end-tt_start << std::endl;
15855  }
15856 
15857  // ------------------------------------------------------------------
15858  // BEGIN: Classify halo(ed) elements and nodes
15859  // ------------------------------------------------------------------
15860  const bool report_stats = true;
15861  DocInfo tmp_doc_info;
15862  tmp_doc_info.disable_doc();
15863 
15864  // Classify nodes
15865  this->classify_halo_and_haloed_nodes(tmp_doc_info,report_stats);
15866 
15867  // Document the timings for reseting halo and haloed scheme (with
15868  // classification of halo and haloed nodes)
15869  if (Print_timings_level_adaptation>1)
15870  {
15871  tt_end = TimingHelpers::timer();
15872  oomph_info
15873  << "CPU for resetting halo-haloed scheme (with classification of halo and haloed nodes): "
15874  << tt_end-tt_start << std::endl;
15875  }
15876 
15877  // ------------------------------------------------------------------
15878  // END: Classify halo(ed) elements and nodes
15879  // ------------------------------------------------------------------
15880 
15881  }
15882 
15883 //======================================================================
15884 // \short Compute the alias of the nodes on shared boundaries in this
15885 // (my_rank) processor with other processors. Also compute the alias
15886 // of nodes on shared boundaries of other processors with other
15887 // processors (useful when there is an element that requires to be
15888 // sent to this (my_rank) processor because there is a shared node
15889 // between this (my_rank) and other processors BUT there is not a
15890 // shared boundary between this and the other processor
15891 // ======================================================================
15892 template <class ELEMENT>
15895  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15896  &other_proc_shd_bnd_node_pt,
15897  Vector<Vector<Vector<unsigned> > > &global_node_names,
15898  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
15899  Vector<Node*> &global_shared_node_pt)
15900 {
15901  // Get the number of processors
15902  const unsigned nproc = this->communicator_pt()->nproc();
15903  // Get the rank of the current processor
15904  const unsigned my_rank = this->communicator_pt()->my_rank();
15905  // Get the communicator of the mesh
15906  OomphCommunicator* comm_pt = this->communicator_pt();
15907 
15908  // ---------------------------------------------------------------
15909  // BEGIN: Get the elements adjacent to shared boundaries and give
15910  // a unique node number to the nodes on the shared boundaries in
15911  // this processor
15912  // ---------------------------------------------------------------
15913 
15914  // Counter for the nodes on shared boundaries in this (my_rank)
15915  // processor
15916  unsigned counter_nodes = 0;
15917  // Keep track of visited nodes
15918  std::map<Node*, bool> done_node;
15919  // ... and its local node number
15920  std::map<Node*, unsigned> local_node_number;
15921  // ... and the inverted relation from local node number to node_pt
15922  Vector<Node*> local_node_pt;
15923 
15924  // Stores the j-th node name associated with the i-th local node
15925  // on shared boundaries in this processor (my_rank)
15926  // local_node_names[i][j][0] = my_rank (this processor)
15927  // local_node_names[i][j][1] = iproc (the processor with which there
15928  // is a shared boundary)
15929  // local_node_names[i][j][2] = the shared boundary id between this
15930  // (my_rank) processor and iproc
15931  // processor
15932  // local_node_names[i][j][3] = the node index on the shared boundary
15933  // local_node_names[i][j][4] = the local node index (i). This may
15934  // be unnecessary since we alread know the
15935  // index but we also send this info. to
15936  // the root processor that is why we store
15937  // them here
15938  Vector<Vector<Vector<unsigned> > > local_node_names;
15939 
15940  // loop over the processors
15941  for (unsigned iproc = 0; iproc < nproc; iproc++)
15942  {
15943  // There are not shared boundaries with myself
15944  if (iproc != my_rank)
15945  {
15946  // Get the number of shared boundaries with iproc
15947  const unsigned n_shd_bnds_with_iproc =
15948  this->nshared_boundaries(my_rank, iproc);
15949 
15950  // Get the boundaries ids shared with iproc
15951  Vector<unsigned> bnd_shd_with_iproc =
15952  this->shared_boundaries_ids(my_rank, iproc);
15953 
15954  // Loop over the shared boundaries with processor iproc
15955  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
15956  {
15957  // Keep track of visited nodes with this shared boundary
15958  std::map<Node*,bool> done_node_shd_bnd;
15959  // The boundary id
15960  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
15961  // Get the number of element on the shared boundary
15962  const unsigned n_shd_bnd_ele =
15963  this->nshared_boundary_element(shd_bnd_id);
15964 
15965  // loop over the elements adjacent to the shared boundary
15966  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
15967  {
15968  // Get the element
15969  FiniteElement* ele_pt =
15970  this->shared_boundary_element_pt(shd_bnd_id, e);
15971 
15972  // Get the number of nodes on the element
15973  const unsigned n_nodes = ele_pt->nnode();
15974 
15975  // loop over the nodes of the current element
15976  for (unsigned n = 0; n < n_nodes; n++)
15977  {
15978  // Get the node
15979  Node* node_pt = ele_pt->node_pt(n);
15980 
15981  // Has the node been visited with this shared boundary?
15982  // And, is this a node on the shd_bnd_id shared boundary
15983  // with processor iproc?
15984  if (!done_node_shd_bnd[node_pt] &&
15985  this->is_node_on_shared_boundary(shd_bnd_id,
15986  node_pt))
15987  {
15988  // Mark the done as done with this shared boundary
15989  done_node_shd_bnd[node_pt] = true;
15990 
15991  // Get the index of the node on the shared boundary
15992  // -------------------------------------------------
15993  // Get the number of nodes on the shared boundary
15994  const unsigned n_nodes_shd_bnd =
15995  nsorted_shared_boundary_node(shd_bnd_id);
15996 
15997  // The index
15998  unsigned index = 0;
15999 
16000 #ifdef PARANOID
16001  // Flag to know if the node has been found
16002  bool found_node_on_shared_boundary = false;
16003 #endif
16004  // Loop over the nodes on the shared boundary to find
16005  // the node
16006  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16007  {
16008  // Get the k-th node on the shared boundary
16009  Node* shd_bnd_node_pt =
16010  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16011 
16012  // Is the same node?
16013  if (shd_bnd_node_pt == node_pt)
16014  {
16015  // This is the index
16016  index = k;
16017 #ifdef PARANOID
16018  // Mark as found
16019  found_node_on_shared_boundary = true;
16020 #endif
16021  break; // break
16022 
16023  } // if (shd_bnd_node_pt == node_pt)
16024 
16025  } // for (k < n_nodes_shd_bnd)
16026 
16027 #ifdef PARANOID
16028  if (!found_node_on_shared_boundary)
16029  {
16030  std::ostringstream error_message;
16031  error_message
16032  <<"The index of the node on boundary ("<<shd_bnd_id
16033  <<") was not found.\n"
16034  <<"These are the node coordinates\n"
16035  <<"("<<node_pt->x(0)<<","<<node_pt->x(1)<<").\n";
16036  throw OomphLibError(error_message.str(),
16037  OOMPH_CURRENT_FUNCTION,
16038  OOMPH_EXCEPTION_LOCATION);
16039  }
16040 #endif
16041 
16042  // Create the node name
16043  Vector<unsigned> node_name(5);
16044  node_name[0] = my_rank;
16045  node_name[1] = iproc;
16046  node_name[2] = shd_bnd_id;
16047  node_name[3] = index;
16048  // The node number is filled in the following if/else
16049  //node_name[4] = ?;
16050 
16051  // Has the node already been visited?
16052  if (!done_node[node_pt])
16053  {
16054  // If not ...
16055 
16056  // Add the node to the local nodes
16057  local_node_pt.push_back(node_pt);
16058 
16059  // Assign a local node number to the node
16060  local_node_number[node_pt] = counter_nodes;
16061  // Store the local node number
16062  node_name[4] = counter_nodes;
16063  // Increase the counter of nodes
16064  counter_nodes++;
16065  // ... and mark it as visited
16066  done_node[node_pt] = true;
16067 
16068  // Push back the node name (the first
16069  // one found for this node)
16070  Vector<Vector<unsigned> > first_node_name(1);
16071  first_node_name[0] = node_name;
16072  local_node_names.push_back(first_node_name);
16073  }
16074  else
16075  {
16076  // If yes ...
16077 
16078  // Get the local node number
16079  unsigned node_number = local_node_number[node_pt];
16080 
16081  // Store the local node number
16082  node_name[4] = node_number;
16083 
16084  // Push back the node name for the
16085  // node number
16086  local_node_names[node_number].push_back(node_name);
16087 
16088  }
16089 
16090  } // Is on shared boundary?
16091 
16092  } // for (n < nnodes)
16093 
16094  } // for (e < n_shd_bnd_ele)
16095 
16096  } // for (ishd < n_shd_bnds_with_iproc)
16097 
16098  } // if (iproc != my_rank)
16099 
16100  } // for (iproc < nproc)
16101 
16102  // ---------------------------------------------------------------
16103  // END: Get the elements adjacent to shared boundaries and give
16104  // a unique node number to the nodes on the shared boundaries in
16105  // this processor
16106  // ---------------------------------------------------------------
16107 
16108  // ---------------------------------------------------------------
16109  // BEGIN: Package the names of the local nodes
16110  // ---------------------------------------------------------------
16111  // Counter for the number of names of the nodes
16112  unsigned n_total_local_names = 0;
16113  // Get the number of local nodes
16114  const unsigned n_local_nodes = local_node_names.size();
16115  // loop over the number of local nodes and get the number of names
16116  // of each node
16117  for (unsigned i = 0; i < n_local_nodes; i++)
16118  {
16119  // Get the number of names of the i-th local node
16120  const unsigned n_inode_names = local_node_names[i].size();
16121  // ... and add them to the total number of local names
16122  n_total_local_names+=n_inode_names;
16123  } // for (i < n_local_nodes)
16124 
16125  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16126  // where node# is the node number on this processor (my_rank)
16127  const unsigned n_info_per_node_name = 5;
16128  // Storage for the flat package
16129  Vector<unsigned> flat_packed_send_udata(n_total_local_names*n_info_per_node_name);
16130  // A counter
16131  unsigned counter = 0;
16132  // loop over the local nodes
16133  for (unsigned i = 0; i < n_local_nodes; i++)
16134  {
16135  // Get the number of names of the i-th local node
16136  const unsigned n_inode_names = local_node_names[i].size();
16137  // loop over the names of the i-th local node
16138  for (unsigned j = 0 ; j < n_inode_names; j++)
16139  {
16140  // Store this processor id (my_rank)
16141  flat_packed_send_udata[counter++]=local_node_names[i][j][0];
16142  // Store the processor with which the shared boundary exist
16143  flat_packed_send_udata[counter++]=local_node_names[i][j][1];
16144  // Store the shared boundary id
16145  flat_packed_send_udata[counter++]=local_node_names[i][j][2];
16146  // Store the index of the node on the shared boundary
16147  flat_packed_send_udata[counter++]=local_node_names[i][j][3];
16148  // Store the local node number on this processor (my_rank)
16149  flat_packed_send_udata[counter++]=local_node_names[i][j][4];
16150  } // for (j < n_inode_names)
16151 
16152  } // for (i < n_local_nodes)
16153 
16154  // Reset the counter
16155  counter = 0;
16156 
16157  // The number of data that will be sent to root from this
16158  // (my_rank) processor
16159  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16160 
16161  // ---------------------------------------------------------------
16162  // END: Package the names of the local nodes
16163  // ---------------------------------------------------------------
16164  // ---------------------------------------------------------------
16165  // BEGIN: Send the data to the root processor
16166  // ---------------------------------------------------------------
16167 
16168  // The root processor is in charge of computing all the node names
16169  // of the nodes on the shared boundaries
16170 
16171  // Choose the root processor
16172  const unsigned root_processor = 0;
16173 
16174  // The vector where the root processor receives how many names
16175  // will receive from the other processors
16176  Vector<unsigned> root_n_names_per_processor(nproc);
16177 
16178  // Send the number of names that the root processor will receive
16179  // from each processor
16180  MPI_Gather(&n_total_local_names, 1, MPI_UNSIGNED,
16181  &root_n_names_per_processor[0], 1, MPI_UNSIGNED,
16182  root_processor, comm_pt->mpi_comm());
16183 
16184  // Get the total number of data to receive from all processor in
16185  // root
16186  unsigned root_n_total_udata_receive = 0;
16187  Vector<int> root_n_udata_to_receive(nproc,0);
16188  for (unsigned iproc = 0; iproc < nproc; iproc++)
16189  {
16190  root_n_udata_to_receive[iproc]=
16191  root_n_names_per_processor[iproc]*n_info_per_node_name;
16192  root_n_total_udata_receive+=root_n_udata_to_receive[iproc];
16193  }
16194 
16195  // Stores and compute the offsets (in root) for the data received
16196  // from each processor
16197  Vector<int> root_uoffsets_receive(nproc,0);
16198  root_uoffsets_receive[0] = 0;
16199  for (unsigned iproc = 1; iproc < nproc; iproc++)
16200  {
16201  // Compute the offset to obtain the data from each processor
16202  root_uoffsets_receive[iproc] =
16203  root_uoffsets_receive[iproc-1] + root_n_udata_to_receive[iproc-1];
16204 
16205  }
16206 
16207  // Create at least one entry so we don't get a seg fault below
16208  if (flat_packed_send_udata.size()==0)
16209  {
16210  flat_packed_send_udata.resize(1);
16211  }
16212 
16213  // Vector where to receive the info on root from all processors
16214  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16215  // Only root receive data, the others dont, then resize the
16216  // container to have at least one entry
16217  if (my_rank!=root_processor)
16218  {
16219  // Create at least one entry so we don't get a seg fault below
16220  if (root_flat_packed_receive_udata.size()==0)
16221  {
16222  root_flat_packed_receive_udata.resize(1);
16223  }
16224  } // if (my_rank!=root_processor)
16225 
16226  // Send the info. to the root processor
16227  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16228  // info. from each
16229  // processor
16230  n_udata_send_to_root, // Total number of data send
16231  // from each processor to root
16232  MPI_UNSIGNED,
16233  &root_flat_packed_receive_udata[0], // Container where
16234  // to receive the
16235  // info. from all
16236  // processors
16237  &root_n_udata_to_receive[0], // Number of data to
16238  // receive from each
16239  // processor
16240  &root_uoffsets_receive[0], // The offset to store the
16241  // info. from each
16242  // processor
16243  MPI_UNSIGNED,
16244  root_processor, //The processor that receives all the
16245  //info.
16246  comm_pt->mpi_comm());
16247 
16248  // Clear and resize the flat package to send
16249  flat_packed_send_udata.clear();
16250  flat_packed_send_udata.resize(0);
16251  // ---------------------------------------------------------------
16252  // END: Send the data to the root processor
16253  // ---------------------------------------------------------------
16254 
16255  // Container where root stores the info. that will be sent to all
16256  // processors. This includes the number of global nodes, the
16257  // number of names for each global node and the names
16258  Vector<unsigned> flat_packed_root_send_receive_udata;
16259 
16260  // ---------------------------------------------------------------
16261  // BEGIN: Unpackage the info. received on root. Compute the alias
16262  // of the nodes
16263  // ---------------------------------------------------------------
16264  if (my_rank == root_processor)
16265  {
16266  // Compute all the names of a node
16267  // root_global_node_name[x][ ][ ] Global node number
16268  // root_global_node_name[ ][x][ ] Global node names
16269  // root_global_node_name[ ][ ][x] Global node info.
16270  Vector<Vector<Vector<unsigned> > > root_global_node_names;
16271 
16272  // Store the info. extracted from the flat package sent to
16273  // root
16274  // root_local_node_names[x][ ] Node name
16275  // root_local_node_names[ ][x] Node info
16276  Vector<Vector<unsigned> > root_local_node_names;
16277 
16278  // Extract all the node names
16279  unsigned rcounter = 0;
16280  // loop over the processors
16281  for (unsigned iproc = 0; iproc < nproc; iproc++)
16282  {
16283  // Get the number of node names received from iproc
16284  const unsigned n_local_names_iproc =
16285  root_n_names_per_processor[iproc];
16286  for (unsigned i = 0; i < n_local_names_iproc; i++)
16287  {
16288  // Get the i-thnode name from iproc
16289  Vector<unsigned> node_name(n_info_per_node_name);
16290  for (unsigned j = 0; j < n_info_per_node_name; j++)
16291  {node_name[j] = root_flat_packed_receive_udata[rcounter++];}
16292 
16293  // Add the i-th node name
16294  root_local_node_names.push_back(node_name);
16295 
16296  } // for (i < n_local_names_iproc)
16297 
16298  } // for (iproc < nproc)
16299 
16300  // Get the number of node names received
16301  const unsigned n_root_local_node_names =
16302  root_local_node_names.size();
16303 
16304  // For each name of the node identify the position of its
16305  // counter-part
16306 
16307  // Given a node name on the iproc,
16308  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16309  // its counter part must live in jproc, so we look for the
16310  // node name
16311  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16312 
16313  // Store the index of the node name counter-part
16314  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16315 
16316  // Keep track of the names of nodes already done
16317  std::map<Vector<unsigned>, bool> done_name;
16318 
16319  // loop over the names of the nodes received from all
16320  // processors
16321  for (unsigned i = 0; i < n_root_local_node_names; i++)
16322  {
16323  // Get the i-th node name
16324  Vector<unsigned> node_name = root_local_node_names[i];
16325 
16326  // Check if this name node has been already done
16327  if (!done_name[node_name])
16328  {
16329  // Mark it as done
16330  done_name[node_name] = true;
16331 #ifdef PARANOID
16332  // Flag to indicate the counter-part name node was
16333  // found
16334  bool found_both_names_node = false;
16335 #endif
16336  // Find the counter-part name node (start from j+1
16337  // since all previous have been found, otherwise we
16338  // would not be here)
16339  for (unsigned j = i+1; j < n_root_local_node_names; j++)
16340  {
16341  Vector<unsigned> node_name_r = root_local_node_names[j];
16342 
16343  // Check if this name node has been already done
16344  if (!done_name[node_name_r])
16345  {
16346  // Check whether this node is the
16347  // counter-part of the current name node
16348  if (node_name[0] == node_name_r[1] &&
16349  node_name[1] == node_name_r[0] &&
16350  node_name[2] == node_name_r[2] &&
16351  node_name[3] == node_name_r[3])
16352  {
16353  // Mark the name as node
16354  done_name[node_name_r] = true;
16355  // Store the index of the counter-part of
16356  // the current node name
16357  node_name_counter_part[i] = j;
16358  // ... and indicate the current node name
16359  // as the index of the counter-part
16360  node_name_counter_part[j] = i;
16361 #ifdef PARANOID
16362  // The node has been found
16363  found_both_names_node = true;
16364 #endif
16365  // Break the loop to find the
16366  // counter-part
16367  break;
16368  }
16369 
16370  } // if (!done_name[node_name_r])
16371 
16372  } // for (j < n_root_local_node_names)
16373 #ifdef PARANOID
16374  // Check whether the node counter-part was found
16375  if (!found_both_names_node)
16376  {
16377  std::ostringstream error_message;
16378  error_message
16379  <<"The counter-part of the current name node was "
16380  <<"not found,\nthe current node name is:\n"
16381  <<"iproc:("<<node_name[0]<<")\n"
16382  <<"jproc:("<<node_name[1]<<")\n"
16383  <<"ishd_bnd:("<<node_name[2]<<")\n"
16384  <<"index:("<<node_name[3]<<")\n";
16385  throw OomphLibError(error_message.str(),
16386  OOMPH_CURRENT_FUNCTION,
16387  OOMPH_EXCEPTION_LOCATION);
16388  } // if (!found_both_names_node)
16389 #endif
16390 
16391  } // if (!done_name[node_name])
16392 
16393  } // for (i < n_root_local_node_names)
16394 
16395  // -----------------------------------------------------------
16396  // Look for all the names of each node received and store them
16397  // in the "global node names" container
16398 
16399  // Keep track of the names of nodes already done
16400  done_name.clear();
16401  // loop over the names of the nodes received from all
16402  // processors
16403  for (unsigned i = 0; i < n_root_local_node_names; i++)
16404  {
16405  // Get the i-th node name
16406  Vector<unsigned> node_name = root_local_node_names[i];
16407 
16408  // Check if this name node has been already done
16409  if (!done_name[node_name])
16410  {
16411  // Store all the names of the current node
16412  Vector<Vector<unsigned> > all_node_names;
16413 
16414  // Add the name of the node as the initial node name
16415  all_node_names.push_back(node_name);
16416 
16417  // Get the index of the counter-part
16418  unsigned idx_c = node_name_counter_part[i];
16419  // Get the counter-part of the node name
16420  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16421 
16422  // Add the name of the counter-part of the node
16423  all_node_names.push_back(node_name_r);
16424  // We do not mark it as done since we are interested in
16425  // the names that the counter-part may generate
16426 
16427  // Get the number of names for the current node (two at
16428  // the first time)
16429  unsigned n_current_names = all_node_names.size();
16430  // Counter to ensure to visit all the names of the current
16431  // node
16432  unsigned icounter = 0;
16433 
16434  // Visit all the names of the current node
16435  while(icounter < n_current_names)
16436  {
16437  // Get the current node name
16438  Vector<unsigned> current_node_name = all_node_names[icounter];
16439 
16440  // Search for other names for the current name of the
16441  // node, but first check if this has been already
16442  // visited
16443  if (!done_name[current_node_name])
16444  {
16445  // Mark it as done
16446  done_name[current_node_name] = true;
16447 
16448  // loop over the names of the nodes (start from the
16449  // j+1 position, all previous node names have all
16450  // their names already assigned)
16451  for (unsigned j=i+1;j<n_root_local_node_names;j++)
16452  {
16453  // Get the j-th node name
16454  Vector<unsigned> other_node_name = root_local_node_names[j];
16455 
16456  // Is this name node already done
16457  if (!done_name[other_node_name])
16458  {
16459  // Is this another name for the current name node?
16460  if ((current_node_name[0] == other_node_name[0]) &&
16461  (current_node_name[4] == other_node_name[4]))
16462  {
16463  // Mark it as done. If we search again using the
16464  // "other_node_name" as the current node name we
16465  // are not going to find new nodes to add
16466  done_name[other_node_name] = true;
16467  // Before adding it check that it is not already
16468  // part of the names of the node
16469  Vector<Vector<unsigned> >::iterator it
16470  = std::find(all_node_names.begin(),
16471  all_node_names.end(),
16472  other_node_name);
16473  if (it==all_node_names.end())
16474  {
16475  all_node_names.push_back(other_node_name);
16476  // Get the index of the counter-part
16477  unsigned k = node_name_counter_part[j];
16478  // Get the counter-part of the node name
16479  Vector<unsigned> other_node_name_r =
16480  root_local_node_names[k];
16481  // Add the name of the counter-part of the
16482  // node only if it has not been previously
16483  // done
16484  if (!done_name[other_node_name_r])
16485  {
16486  all_node_names.push_back(other_node_name_r);
16487  }
16488 
16489  }
16490 
16491  } // // Is this another name for the current name
16492  // node?
16493 
16494  } // if (!done_name[other_node_name])
16495 
16496  } // for (j < n_root_local_node_names)
16497 
16498  } // if (!done_name[current_node_name])
16499 
16500  // Get the number of names
16501  n_current_names = all_node_names.size();
16502  // Increase the icounter to indicate we have visited the
16503  // current name of the node
16504  icounter++;
16505 
16506  } // while(icounter < n_current_names)
16507 
16508  // We now have all the names for the i-th global node
16509  root_global_node_names.push_back(all_node_names);
16510 
16511  } // if (!done_name[node_name])
16512 
16513  } // for (i < n_root_local_node_names)
16514 
16515  // -------------------------------------------------------------
16516  // Prepare the info to be sent to all processors. The number
16517  // of global nodes, the number of names for each global node,
16518  // and their respective names
16519  // -------------------------------------------------------------
16520 
16521  // Clear the container
16522  flat_packed_root_send_receive_udata.clear();
16523  // Get the number of global nodes
16524  const unsigned n_global_nodes = root_global_node_names.size();
16525  // ... and store this info. to be sent from root to all
16526  // processors
16527  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16528 
16529  // loop over the nodes
16530  for (unsigned i = 0; i < n_global_nodes; i++)
16531  {
16532  // Get the names of the i-th global node
16533  Vector<Vector<unsigned> > global_inode_names =
16534  root_global_node_names[i];
16535  // Get the number of names for the i-th global node
16536  const unsigned n_names_global_inode = global_inode_names.size();
16537  // ... and store this info. to be sent from root to all
16538  // processors
16539  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16540  // loop over the names of the global i-th node
16541  for (unsigned j = 0; j < n_names_global_inode; j++)
16542  {
16543  // loop over the info. associated with each name
16544  for (unsigned k = 0; k < n_info_per_node_name; k++)
16545  {
16546  // Store the name info. of the current name in the
16547  // container to be sent from root to all processors
16548  flat_packed_root_send_receive_udata.
16549  push_back(global_inode_names[j][k]);
16550  } // for (k < n_info_per_node_name)
16551 
16552  } // for (j < n_names_inode)
16553 
16554  } // for (i < n_global_nodes)
16555 
16556  } // if (my_rank == root_processor)
16557 
16558  // ----------------------------------------------------------------
16559  // END: Unpackage the info. received on root. Compute the alias
16560  // of the nodes and prepare the info. to be sent back from
16561  // root to all processors
16562  // ----------------------------------------------------------------
16563 
16564  // ---------------------------------------------------------------
16565  // BEGIN: Send the info. back to all processors, unpackage the
16566  // info. and create the map from node name to global node
16567  // index
16568  // ---------------------------------------------------------------
16569  // The number of data that root send to other processors.
16570  unsigned root_n_udata_sent_to_all_proc =
16571  flat_packed_root_send_receive_udata.size();
16572 
16573  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16574  // receive
16575  1, MPI_UNSIGNED, root_processor,
16576  comm_pt->mpi_comm());
16577 
16578  // Resize the container if this is a processor that receives data
16579  if (my_rank != root_processor)
16580  {
16581  flat_packed_root_send_receive_udata.
16582  resize(root_n_udata_sent_to_all_proc);
16583  }
16584 
16585  // Send the info. from root and receive it on all processors
16586  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16587  // from root to
16588  // all
16589  // processors
16590  root_n_udata_sent_to_all_proc, // Number of data sent
16591  // from root to each
16592  // procesor
16593  MPI_UNSIGNED,
16594  root_processor, // The processor that sends all the info.
16595  comm_pt->mpi_comm());
16596 
16597  // Counter to extract the info.
16598  counter = 0;
16599  // Read the number of global nodes
16600  const unsigned n_global_nodes =
16601  flat_packed_root_send_receive_udata[counter++];
16602  // Store the global names of the nodes
16603  // global_node_name[x][ ][ ] Global node number
16604  // global_node_name[ ][x][ ] Global node names
16605  // global_node_name[ ][ ][x] Global node info.
16606  //Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16607  // Resize the input vector
16608  global_node_names.resize(n_global_nodes);
16609  // Now loop until all global nodes info. has been read
16610  unsigned n_read_global_nodes = 0;
16611  while (n_read_global_nodes < n_global_nodes)
16612  {
16613  // Read the number of names for the current global node
16614  const unsigned n_names_global_inode =
16615  flat_packed_root_send_receive_udata[counter++];
16616  // Counter for the global node
16617  const unsigned i = n_read_global_nodes;
16618  // Resize the container
16619  global_node_names[i].resize(n_names_global_inode);
16620  // loop over the names of the global inode
16621  for (unsigned j = 0; j < n_names_global_inode; j++)
16622  {
16623  // Resize the container
16624  global_node_names[i][j].resize(n_info_per_node_name);
16625  // loop over the info. of the j-th node name of the i-th
16626  // global node
16627  for (unsigned k = 0; k < n_info_per_node_name; k++)
16628  {
16629  // Read the k-th node info. from the j-th node name of
16630  // the i-th global node
16631  global_node_names[i][j][k] =
16632  flat_packed_root_send_receive_udata[counter++];
16633 
16634  } // for (k < n_info_per_node_name)
16635 
16636  // Create the map from the node name to the global node
16637  // index
16638  Vector<unsigned> node_name(n_info_per_node_name-1);
16639  node_name[0] = global_node_names[i][j][0];
16640  node_name[1] = global_node_names[i][j][1];
16641  node_name[2] = global_node_names[i][j][2];
16642  node_name[3] = global_node_names[i][j][3];
16643  // Do not add the local index since it will not longer be
16644  // used. Additionally, we will not know the local node
16645  // index outside this method
16646  // node_name[4] = global_node_names[i][j][4];
16647  node_name_to_global_index[node_name] = i;
16648 
16649  } // for (j < n_names_global_inode)
16650 
16651  // Increase the counter for read global nodes
16652  n_read_global_nodes++;
16653 
16654  } // while (n_read_global_nodes < n_global_nodes)
16655 
16656 #ifdef PARANOID
16657  // Check we have read all the info.
16658  if (counter != root_n_udata_sent_to_all_proc)
16659  {
16660  std::ostringstream error_stream;
16661  error_stream
16662  <<"The info. received from root regarding the global names of "
16663  <<"the nodes\nwas not completely read.\n"
16664  << "The number of data sent/received from root is: ("
16665  <<root_n_udata_sent_to_all_proc<<")\n"
16666  <<"The number of data read from the received info. is: ("
16667  <<counter<<")\n\n";
16668  throw OomphLibError(error_stream.str(),
16669  OOMPH_CURRENT_FUNCTION,
16670  OOMPH_EXCEPTION_LOCATION);
16671  } // if (counter != root_n_udata_sent_to_all_proc)
16672 #endif
16673 
16674  // ---------------------------------------------------------------
16675  // END: Send the info. back to all processors, unpackage the info.
16676  // and create the map from node name to global node index
16677  // ---------------------------------------------------------------
16678 
16679  // ---------------------------------------------------------------
16680  // BEGIN: Add the info. from the global node names into the
16681  // info. of the local node names. We do this because the
16682  // local node names have pointers to the nodes.
16683  // Additionally, create a map from the node name to the
16684  // index of its global node
16685  // ---------------------------------------------------------------
16686 
16687  // Resize the global shared node pointers container
16688  global_shared_node_pt.resize(n_global_nodes, 0);
16689 
16690  // loop over the number of global nodes
16691  for (unsigned i = 0; i < n_global_nodes; i++)
16692  {
16693  // Flag to indicate that the iglobal node is part of the nodes
16694  // on the current processor
16695  bool is_this_a_local_node_name = false;
16696  unsigned local_node_number;
16697  // Get the number of names of the i-th global node
16698  const unsigned n_names_global_inode = global_node_names[i].size();
16699  // loop over the names of the i-th global node
16700  for (unsigned j = 0; j < n_names_global_inode; j++)
16701  {
16702  // Get the node name info.
16703  const unsigned iproc = global_node_names[i][j][0];
16704  local_node_number = global_node_names[i][j][4];
16705 
16706  // Check if this node name lives on this processor
16707  if (my_rank == iproc)
16708  {
16709  // The node is part of the local node names
16710  is_this_a_local_node_name = true;
16711  // Break
16712  break;
16713  } // if (my_rank == iproc)
16714 
16715  } // for (j < n_names_global_inode)
16716 
16717  // If the node is part of the local nodes then add the
16718  // additional names of the node in the local container
16719  if (is_this_a_local_node_name)
16720  {
16721 #ifdef PARANOID
16722  // Check that the global node include at least all the names
16723  // of the node on this processor
16724  const unsigned n_names_local_node =
16725  local_node_names[local_node_number].size();
16726  unsigned n_names_found_on_global_name_node = 0;
16727 #endif
16728 
16729  // Add the pointer of the node into the global shared node
16730  // pointers container
16731  global_shared_node_pt[i] = local_node_pt[local_node_number];
16732 
16733  // Add all the global names of the node onto the local node
16734  // names
16735 
16736  // loop again over the names of the i-th global node
16737  for (unsigned j = 0; j < n_names_global_inode; j++)
16738  {
16739  // Get the node name info.
16740  const unsigned iproc = global_node_names[i][j][0];
16741 
16742  // Is this a node name on this processor?
16743  if (iproc != my_rank)
16744  {
16745  // Add the name
16746  local_node_names[local_node_number].
16747  push_back(global_node_names[i][j]);
16748  }
16749 #ifdef PARANOID
16750  else
16751  {
16752  const unsigned jproc = global_node_names[i][j][1];
16753  const unsigned ishd_bnd = global_node_names[i][j][2];
16754  const unsigned idx = global_node_names[i][j][3];
16755  const unsigned n_local_node = global_node_names[i][j][4];
16756  // loop over the names of the local node
16757  for (unsigned k = 0; k < n_names_local_node; k++)
16758  {
16759  if ((local_node_names[local_node_number][k][0] == iproc) &&
16760  (local_node_names[local_node_number][k][1] == jproc) &&
16761  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16762  (local_node_names[local_node_number][k][3] == idx) &&
16763  (local_node_names[local_node_number][k][4] == n_local_node))
16764  {
16765  // Increase the number of local nodes found on the
16766  // global nodes
16767  n_names_found_on_global_name_node++;
16768  } // found global node on local nodes
16769 
16770  } // for (k < n_names_local_node)
16771 
16772  } // if (iproc != my_rank)
16773 #endif
16774 
16775  } // for (j < n_names_global_inode)
16776 
16777 #ifdef PARANOID
16778  // The number of local nodes names must be the same as the the
16779  // number of global nodes names associated with this processor
16780  // (my_rank, that start with iproc = my_rank)
16781  if (n_names_local_node != n_names_found_on_global_name_node)
16782  {
16783  std::ostringstream error_stream;
16784  error_stream
16785  <<"The local node names corresponding to the local "
16786  <<"node ("<< local_node_number << ") were\n"
16787  <<"not found on the global node names.\n\n"
16788  << "These are the names of the local node\n"
16789  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16790  for (unsigned k = 0; k < n_names_local_node; k++)
16791  {
16792  error_stream<<"Name("<<k<<"): "
16793  <<local_node_names[local_node_number][k][0]
16794  <<", "<<local_node_names[local_node_number][k][1]
16795  <<", "<<local_node_names[local_node_number][k][2]
16796  <<", "<<local_node_names[local_node_number][k][3]
16797  <<", "<<local_node_names[local_node_number][k][4]
16798  <<"\n";
16799  }
16800 
16801  error_stream
16802  << "\n\nThese are the names of the global node\n"
16803  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16804  for (unsigned k = 0; k < n_names_global_inode; k++)
16805  {
16806  error_stream<<"Name("<<k<<"): "
16807  <<global_node_names[i][k][0] <<", "
16808  <<global_node_names[i][k][1] <<", "
16809  <<global_node_names[i][k][2] <<", "
16810  <<global_node_names[i][k][3] <<", "
16811  <<global_node_names[i][k][4] <<"\n";
16812  }
16813 
16814  throw OomphLibError(error_stream.str(),
16815  OOMPH_CURRENT_FUNCTION,
16816  OOMPH_EXCEPTION_LOCATION);
16817  }
16818 #endif
16819 
16820  } // if (is_this_a_local_node_name)
16821 
16822  } // for (i < n_global_nodes)
16823 
16824  // ---------------------------------------------------------------
16825  // END: Add the info. from the global node names into the info.
16826  // of the local node names. We do this because the local
16827  // node names have pointers to the nodes
16828  // ---------------------------------------------------------------
16829 
16830  // ---------------------------------------------------------------
16831  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16832  // the local nodes.
16833  // ---------------------------------------------------------------
16834 
16835  // Loop over the local nodes and fill the
16836  // other_proc_shd_bnd_node_pt container with the corresponding
16837  // info. NOTE: We are using the old size of the local node names,
16838  // before adding the names of the global nodes so we only loop
16839  // over the local nodes and not global.
16840 
16841  // Compute the local shared boudary id
16842  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
16843 
16844  // loop over the local nodes names
16845  for (unsigned i = 0 ; i < n_local_nodes; i++)
16846  {
16847  // Get the number of names for the i-th local node
16848  const unsigned n_names = local_node_names[i].size();
16849  // Get a pointer to the first name of the node found on this
16850  // processor (this ensures that the node lives on this
16851  // processor)
16852  Node* node_pt = local_node_pt[i];
16853  // loop over the names of the i-th local node and add an entry
16854  // to the other_proc_shd_bnd_node_pt structure
16855  for (unsigned j = 0; j < n_names; j++)
16856  {
16857  // Get the node name info.
16858  const unsigned iproc = local_node_names[i][j][0];
16859  const unsigned jproc = local_node_names[i][j][1];
16860  const unsigned ishd_bnd =
16861  local_node_names[i][j][2] - initial_shd_bnd_id;
16862  const unsigned index = local_node_names[i][j][3];
16863  // We can ignore the last entry, it was just used to compute
16864  // the global node number by the root processor
16865 
16866  // Get the smallest processor number
16867  if (iproc < jproc)
16868  {
16869  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]=node_pt;
16870  }
16871  else
16872  {
16873  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]=node_pt;
16874  }
16875 
16876  } // for (j < n_names)
16877 
16878  } // for (i < n_local_node_names)
16879 
16880  // ---------------------------------------------------------------
16881  // END: Fill the data structure other_proc_shd_bnd_node_pt with
16882  // the local nodes.
16883  // ---------------------------------------------------------------
16884 
16885 }
16886 
16887  //======================================================================
16888  // \short Get the original boundaries to which is associated each
16889  // shared node, and send the info. to the related processors. We
16890  // need to do this so that at the reset of halo(ed) info. stage,
16891  // the info. is updated
16892 template <class ELEMENT>
16895  Vector<Vector<Vector<unsigned> > > &global_node_names,
16896  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
16897  Vector<Node*> &global_shared_node_pt)
16898 {
16899  // Get the rank and number of processors
16900  const unsigned nproc = this->communicator_pt()->nproc();
16901  const unsigned my_rank = this->communicator_pt()->my_rank();
16902 
16903  // The number of nodes on shared boundaries
16904  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
16905  // ---------------------------------------------------------
16906  // BEGIN: Get the shared nodes between each of processors
16907  // ---------------------------------------------------------
16908 
16909  // Store the nodes on shared boundaries in this processor with other
16910  // processors
16911  Vector<std::set<Node*> > node_on_shd_bnd_pt(nproc);
16912 
16913  // A map to get access to the global shared node number from the
16914  // node pointer
16915  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
16916 
16917  // loop over the global nodes names and get only those in this
16918  // processor
16919  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
16920  {
16921  // Get the number of names of the current node on shared
16922  // boundaries
16923  const unsigned n_names = global_node_names[i].size();
16924  // loop over the names
16925  for (unsigned j = 0; j < n_names; j++)
16926  {
16927  // Store the node name
16928  Vector<unsigned> node_name(4);
16929  node_name[0] = global_node_names[i][j][0];
16930  node_name[1] = global_node_names[i][j][1];
16931  node_name[2] = global_node_names[i][j][2];
16932  node_name[3] = global_node_names[i][j][3];
16933 
16934  // Check whether the node is in the current processor
16935  if (node_name[0]==my_rank)
16936  {
16937  // Check with which processor the node is shared
16938  const unsigned jproc = node_name[1];
16939 
16940 #ifdef PARANOID
16941  std::map<Vector<unsigned>, unsigned>::iterator it =
16942  node_name_to_global_index.find(node_name);
16943  if (it!=node_name_to_global_index.end())
16944  {
16945  // Check whether the global node index correspond with that
16946  // of the current global node name
16947  if (i!=(*it).second)
16948  {
16949  std::ostringstream error_message;
16950  error_message
16951  <<"The global node number "<<(*it).second
16952  <<") obtained from the current node\n"
16953  <<"name is not the same as the current node number ("
16954  <<i<<").\n\n"
16955  <<"Node name:\n"
16956  <<"iproc:"<<node_name[0]<<"\n"
16957  <<"jproc:"<<node_name[1]<<"\n"
16958  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16959  <<"index:"<<node_name[3]<<"\n\n";
16960  throw OomphLibError(error_message.str(),
16961  OOMPH_CURRENT_FUNCTION,
16962  OOMPH_EXCEPTION_LOCATION);
16963  }
16964 
16965  }
16966  else
16967  {
16968  std::ostringstream error_message;
16969  error_message
16970  <<"The node name is not registerd as living in this processor.\n"
16971  <<"Node name:\n"
16972  <<"iproc:"<<node_name[0]<<"\n"
16973  <<"jproc:"<<node_name[1]<<"\n"
16974  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16975  <<"index:"<<node_name[3]<<"\n\n";
16976  throw OomphLibError(error_message.str(),
16977  OOMPH_CURRENT_FUNCTION,
16978  OOMPH_EXCEPTION_LOCATION);
16979  }
16980 
16981 #endif // #ifdef PARANOID
16982 
16983  // Get the node pointer
16984  Node* node_pt = global_shared_node_pt[i];
16985 
16986 #ifdef PARANOID
16987  if (node_pt == 0)
16988  {
16989  std::ostringstream error_message;
16990  error_message
16991  <<"There is not global shared node within this\n"
16992  <<"global node number ("<<i<<"). The global shared\n"
16993  <<"node pointer is null\n\n";
16994  throw OomphLibError(error_message.str(),
16995  OOMPH_CURRENT_FUNCTION,
16996  OOMPH_EXCEPTION_LOCATION);
16997  }
16998 #endif // #ifdef PARANOID
16999 
17000  // Add the node to the nodes on shared boundaries in this
17001  // processor
17002  node_on_shd_bnd_pt[jproc].insert(node_pt);
17003 
17004  // And store the global node index
17005  node_pt_to_global_shd_bnd_index[node_pt] = i;
17006 
17007  } // if (node_name[0]==my_rank)
17008  else if (node_name[1]==my_rank)
17009  {
17010  // Check with which processor the node is shared
17011  const unsigned jproc = node_name[0];
17012 
17013 #ifdef PARANOID
17014  std::map<Vector<unsigned>, unsigned>::iterator it =
17015  node_name_to_global_index.find(node_name);
17016  if (it!=node_name_to_global_index.end())
17017  {
17018  // Check whether the global node index correspond with that
17019  // of the current global node name
17020  if (i!=(*it).second)
17021  {
17022  std::ostringstream error_message;
17023  error_message
17024  <<"The global node number "<<(*it).second
17025  <<") obtained from the current node\n"
17026  <<"name is not the same as the current node number ("
17027  <<i<<").\n\n"
17028  <<"Node name:\n"
17029  <<"iproc:"<<node_name[0]<<"\n"
17030  <<"jproc:"<<node_name[1]<<"\n"
17031  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17032  <<"index:"<<node_name[3]<<"\n\n";
17033  throw OomphLibError(error_message.str(),
17034  OOMPH_CURRENT_FUNCTION,
17035  OOMPH_EXCEPTION_LOCATION);
17036  }
17037 
17038  }
17039  else
17040  {
17041  std::ostringstream error_message;
17042  error_message
17043  <<"The node name is not registerd as living in this processor.\n"
17044  <<"Node name:\n"
17045  <<"iproc:"<<node_name[0]<<"\n"
17046  <<"jproc:"<<node_name[1]<<"\n"
17047  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17048  <<"index:"<<node_name[3]<<"\n\n";
17049  throw OomphLibError(error_message.str(),
17050  OOMPH_CURRENT_FUNCTION,
17051  OOMPH_EXCEPTION_LOCATION);
17052  }
17053 
17054 #endif // #ifdef PARANOID
17055 
17056  // Get the node pointer
17057  Node* node_pt = global_shared_node_pt[i];
17058 
17059 #ifdef PARANOID
17060  if (node_pt == 0)
17061  {
17062  std::ostringstream error_message;
17063  error_message
17064  <<"There is not global shared node within this\n"
17065  <<"global node number ("<<i<<"). The global shared\n"
17066  <<"node pointer is null\n\n";
17067  throw OomphLibError(error_message.str(),
17068  OOMPH_CURRENT_FUNCTION,
17069  OOMPH_EXCEPTION_LOCATION);
17070  }
17071 #endif // #ifdef PARANOID
17072 
17073  // Add the node to the nodes on shared boundaries in this
17074  // processor
17075  node_on_shd_bnd_pt[jproc].insert(node_pt);
17076 
17077  // And store the global node index
17078  node_pt_to_global_shd_bnd_index[node_pt] = i;
17079 
17080  }
17081 
17082  } // for (j < n_names)
17083 
17084  } // for (i < n_nodes_on_shd_bnds)
17085 
17086  // ---------------------------------------------------------
17087  // END: Get the shared nodes between each of processors
17088  // ---------------------------------------------------------
17089 
17090  // ---------------------------------------------------------
17091  // BEGIN: Get the original boundaries associated to each
17092  // node on a shared boundary
17093  // ---------------------------------------------------------
17094 
17095  // Store the global shared node number
17096  Vector<Vector<unsigned> > global_node_on_shared_bound(nproc);
17097  // Store the boundaries associated with the global shared node
17098  // number
17099  Vector<Vector<Vector<unsigned> > > global_node_original_boundaries(nproc);
17100  // Store the zeta boundary coordinate of the nodes on original
17101  // boundaries
17102  Vector<Vector<Vector<double> > > global_node_zeta_coordinate(nproc);
17103 
17104  // loop over the processors
17105  for (unsigned iproc = 0; iproc < nproc; iproc++)
17106  {
17107  // Get the nodes added to be shared with the iproc processor
17108  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17109 
17110  // loop over the nodes
17111  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17112  it!=nodes_shared_pt.end(); it++)
17113  {
17114  // Get the node
17115  Node* node_pt = (*it);
17116  // Store the boundaries on which it is stored
17117  Vector<unsigned> on_original_boundaries;
17118  // For each boundary get the corresponding z value of the node
17119  // on the boundary
17120  Vector<double> zeta_coordinate;
17121  // Get the number of boudandaries
17122  const unsigned n_bnd=this->initial_shared_boundary_id();
17123  // loop over the boundaries and register the boundaries to which
17124  // it is associated
17125  for (unsigned bb = 0; bb < n_bnd; bb++)
17126  {
17127  // Is the node on original boundary bb?
17128  if (node_pt->is_on_boundary(bb))
17129  {
17130  // Then save it as being on boundary bb
17131  on_original_boundaries.push_back(bb);
17132  // Get the boundary coordinate
17133  Vector<double> zeta(1);
17134  node_pt->get_coordinates_on_boundary(bb, zeta);
17135  // Save the boundary coordinate
17136  zeta_coordinate.push_back(zeta[0]);
17137  }
17138 
17139  } // for (bb < n_bnd)
17140 
17141  // Is the node on an original boundary
17142  if (on_original_boundaries.size()>0)
17143  {
17144  // Get the global shared node number
17145  std::map<Node*,unsigned>::iterator it_index =
17146  node_pt_to_global_shd_bnd_index.find(node_pt);
17147 #ifdef PARANOID
17148  if (it_index==node_pt_to_global_shd_bnd_index.end())
17149  {
17150  std::ostringstream error_message;
17151  error_message
17152  <<"We could not find the global shared node index associated\n"
17153  <<"with the node pointer with vertices coordinates:\n"
17154  <<"("<<node_pt->x(0)<<", "<<node_pt->x(1)<<")\n\n";
17155  throw OomphLibError(error_message.str(),
17156  OOMPH_CURRENT_FUNCTION,
17157  OOMPH_EXCEPTION_LOCATION);
17158  }
17159 #endif
17160  // The global shared node index
17161  const unsigned global_shared_node_number = (*it_index).second;
17162  // Store the global shared node number
17163  global_node_on_shared_bound[iproc].push_back(global_shared_node_number);
17164  // And store the original boundaries to which it is associated
17165  global_node_original_boundaries[iproc].
17166  push_back(on_original_boundaries);
17167  // and the corresponding zeta coordinate
17168  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17169  }
17170 
17171  } // loop over nodes on shared boundaries with iproc
17172 
17173  } // for (iproc < nproc)
17174 
17175  // ---------------------------------------------------------
17176  // END: Get the original boundaries associated to each
17177  // node on a shared boundary
17178  // ---------------------------------------------------------
17179 
17180  // ---------------------------------------------------------
17181  // BEGIN: Send the info. to the corresponding processors,
17182  // package the info, send it and receive it in the
17183  // corresponding processor, unpackage and set the
17184  // boundaries associated with the received nodes
17185  // ---------------------------------------------------------
17186 
17187  // Get the communicator of the mesh
17188  OomphCommunicator* comm_pt = this->communicator_pt();
17189 
17190  // Set MPI info
17191  MPI_Status status;
17192  MPI_Request request;
17193 
17194  // loop over the processors
17195  for (unsigned iproc = 0; iproc < nproc; iproc++)
17196  {
17197  // The number of nodes shared between the pair of processors
17198  const unsigned n_shd_nodes_my_rank_iproc =
17199  node_on_shd_bnd_pt[iproc].size();
17200 
17201  // Are there shared nodes between these pair of processors
17202  // (my_rank, iproc)? Also ensure not to send info. within myself
17203  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17204  {
17205  // The flat package to send the info, to the iproc processor
17206  Vector<unsigned> flat_package_unsigned_send;
17207  // The very first entry is the number of nodes shared by the
17208  // pair of processors (my_rank, iproc)
17209  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17210 
17211  // Get the number of shared nodes on original boundaries
17212  const unsigned n_global_shared_node_on_original_boundary =
17213  global_node_on_shared_bound[iproc].size();
17214 
17215  // The second data is the number of shared nodes on original
17216  // boundaries
17217  flat_package_unsigned_send.
17218  push_back(n_global_shared_node_on_original_boundary);
17219 
17220  // ... also send the zeta coordinates associated with the
17221  // original boundaries
17222  Vector<double> flat_package_double_send;
17223 
17224  // loop over the nodes shared between this pair of processors
17225  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17226  {
17227  // Get the global shared node index
17228  const unsigned global_shared_node_index =
17229  global_node_on_shared_bound[iproc][i];
17230 
17231  // Put in the package the shared node index of the current
17232  // node
17233  flat_package_unsigned_send.push_back(global_shared_node_index);
17234 
17235  // Get the original boundaries to which the node is associated
17236  Vector<unsigned> on_original_boundaries =
17237  global_node_original_boundaries[iproc][i];
17238 
17239  // Get the associated zeta boundary coordinates
17240  Vector<double> zeta_coordinate =
17241  global_node_zeta_coordinate[iproc][i];
17242 
17243  // Get the number of original boundaries to which the node is
17244  // associated
17245  const unsigned n_original_boundaries =
17246  on_original_boundaries.size();
17247 
17248  // Put in the package the number of original boundaries the
17249  // node is associated
17250  flat_package_unsigned_send.push_back(n_original_boundaries);
17251 
17252  // loop over the original boundaries ids and include them in
17253  // the package
17254  for (unsigned j = 0; j < n_original_boundaries; j++)
17255  {
17256  // Put in the package each of the original boundaries to
17257  // which it is associated
17258  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17259  // The zeta coordinate on the boundary
17260  flat_package_double_send.push_back(zeta_coordinate[j]);
17261  } // for (j < n_original_boundaries)
17262 
17263  } // for (i < n_global_shared_node_on_original_boundary)
17264 
17265  // Send data UNSIGNED -----------------------------------------
17266  // Get the size of the package to communicate to the iproc
17267  // processor
17268  const unsigned n_udata_send = flat_package_unsigned_send.size();
17269  int n_udata_send_int = n_udata_send;
17270 
17271  // Send/receive data to/from iproc processor
17272  MPI_Isend(&n_udata_send_int,1,MPI_UNSIGNED,
17273  iproc,1,comm_pt->mpi_comm(), &request);
17274 
17275  int n_udata_received_int = 0;
17276  MPI_Recv(&n_udata_received_int,1,MPI_UNSIGNED,
17277  iproc,1,comm_pt->mpi_comm(),&status);
17278  MPI_Wait(&request,MPI_STATUS_IGNORE);
17279 
17280  if (n_udata_send!=0)
17281  {
17282  MPI_Isend(&flat_package_unsigned_send[0],
17283  n_udata_send,MPI_UNSIGNED,
17284  iproc,2,comm_pt->mpi_comm(),&request);
17285  }
17286 
17287  const unsigned n_udata_received =
17288  static_cast<unsigned>(n_udata_received_int);
17289 
17290  // Where to receive the data from the iproc processor
17291  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17292 
17293  if (n_udata_received!=0)
17294  {
17295  MPI_Recv(&flat_package_unsigned_receive[0],
17296  n_udata_received,MPI_UNSIGNED,
17297  iproc,2,comm_pt->mpi_comm(),&status);
17298  }
17299 
17300  if (n_udata_send!=0)
17301  {
17302  MPI_Wait(&request,MPI_STATUS_IGNORE);
17303  }
17304 
17305  // Send data DOUBLE -----------------------------------------
17306  // Get the size of the package to communicate to the iproc
17307  // processor
17308  const unsigned n_ddata_send = flat_package_double_send.size();
17309  int n_ddata_send_int = n_ddata_send;
17310 
17311  // Send/receive data to/from iproc processor
17312  MPI_Isend(&n_ddata_send_int,1,MPI_UNSIGNED,
17313  iproc,1,comm_pt->mpi_comm(), &request);
17314 
17315  int n_ddata_received_int = 0;
17316  MPI_Recv(&n_ddata_received_int,1,MPI_UNSIGNED,
17317  iproc,1,comm_pt->mpi_comm(),&status);
17318  MPI_Wait(&request,MPI_STATUS_IGNORE);
17319 
17320  if (n_ddata_send!=0)
17321  {
17322  MPI_Isend(&flat_package_double_send[0],
17323  n_ddata_send,MPI_DOUBLE,
17324  iproc,2,comm_pt->mpi_comm(),&request);
17325  }
17326 
17327  const unsigned n_ddata_received =
17328  static_cast<unsigned>(n_ddata_received_int);
17329 
17330  // Where to receive the data from the iproc processor
17331  Vector<double> flat_package_double_receive(n_ddata_received);
17332 
17333  if (n_ddata_received!=0)
17334  {
17335  MPI_Recv(&flat_package_double_receive[0],
17336  n_ddata_received,MPI_DOUBLE,
17337  iproc,2,comm_pt->mpi_comm(),&status);
17338  }
17339 
17340  if (n_ddata_send!=0)
17341  {
17342  MPI_Wait(&request,MPI_STATUS_IGNORE);
17343  }
17344 
17345  // Unpackage -------------------------------------------------
17346  // ... and associate the nodes to the corresponding original
17347  // boundaries
17348 
17349  // The number of nodes to be received
17350  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17351 
17352  // Increase and decrease the number of received shared nodes to
17353  // avoid the warning when compiling without PARANOID
17354  n_shared_nodes_received++;
17355  n_shared_nodes_received--;
17356 
17357 #ifdef PARANOID
17358  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17359  {
17360  std::ostringstream error_message;
17361  error_message
17362  <<"The number of shared nodes between the pair of processors is\n"
17363  <<"not the same\n"
17364  <<"N.shared nodes proc ("<<my_rank<<") with proc ("<<iproc<<"): ("
17365  <<n_shd_nodes_my_rank_iproc<<"\n"
17366  <<"N.shared nodes proc ("<<iproc<<") with proc ("<<my_rank<<"): ("
17367  <<n_shared_nodes_received<<"\n\n"
17368  <<"You should have got the same error in proc: ("<<iproc<<")\n\n";
17369  throw OomphLibError(error_message.str(),
17370  OOMPH_CURRENT_FUNCTION,
17371  OOMPH_EXCEPTION_LOCATION);
17372  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17373 #endif
17374 
17375  // Skip the number of nodes on shared boundaries on original
17376  // boundaries received (that is why next lines are commented)
17377 
17378  // The number of nodes on shared boundaries on original
17379  // boundaries
17380  //const unsigned n_shared_nodes_on_original_boundaries_received =
17381  // flat_package_unsigned_receive[1];
17382 
17383  // loop over the received info.
17384  unsigned current_index_data = 2;
17385  unsigned current_index_ddata = 0;
17386  while(current_index_data < n_udata_received)
17387  {
17388  // The global shared node number
17389  const unsigned global_shared_node_index =
17390  flat_package_unsigned_receive[current_index_data++];
17391 
17392  // The pointer to the node
17393  Node* node_pt = 0;
17394 
17395  // The number of original boundaries the node is associated
17396  // with
17397  const unsigned n_original_boundaries =
17398  flat_package_unsigned_receive[current_index_data++];
17399 
17400  // Get the node pointer
17401  node_pt = global_shared_node_pt[global_shared_node_index];
17402 #ifdef PARANOID
17403  if (node_pt == 0)
17404  {
17405  std::ostringstream error_message;
17406  error_message
17407  <<"The global shared node ("<<global_shared_node_index<<") "
17408  <<"could not be found in this processor!!!\n"
17409  <<"However, it was found in processor ("<<iproc<<"). The "
17410  <<"data may be no synchronised,\ntherefore "
17411  <<"we may be looking for a global shared node number that "
17412  <<"do not\ncorrespond with the one that was sent by "
17413  <<"processor ("<<iproc<<")\n\n";
17414  throw OomphLibError(error_message.str(),
17415  OOMPH_CURRENT_FUNCTION,
17416  OOMPH_EXCEPTION_LOCATION);
17417  }
17418 #endif // #ifdef PARANOID
17419 
17420  // loop over the number of original boundaries and associate
17421  // the node to each of those boundaries
17422  for (unsigned i = 0; i < n_original_boundaries; i++)
17423  {
17424  // Get the original boundary to which the node is associated
17425  // with
17426  const unsigned original_bound_id =
17427  flat_package_unsigned_receive[current_index_data++];
17428 
17429  // Associate the node with the boundary
17430  this->add_boundary_node(original_bound_id, node_pt);
17431 
17432  // Get the zeta boundary coordinate
17433  Vector<double> zeta(1);
17434  zeta[0] = flat_package_double_receive[current_index_ddata++];
17435  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17436  }
17437 
17438  } // while(current_data < n_data_received)
17439 
17440  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17441 
17442  } // for (iproc < nproc)
17443 
17444  // ---------------------------------------------------------
17445  // END: Send the info. to the corresponding processors,
17446  // package the info, send it and receive it in the
17447  // corresponding processor, unpackage and set the
17448  // boundaries associated with the received nodes
17449  // ---------------------------------------------------------
17450 
17451 }
17452 
17453  //======================================================================
17454  // \short In charge of creating additional halo(ed) elements on those
17455  // processors that have no shared boundaries in common but have
17456  // shared nodes
17457  // ======================================================================
17458 template <class ELEMENT>
17460  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
17461  &other_proc_shd_bnd_node_pt,
17462  Vector<Vector<Node *> > &iproc_currently_created_nodes_pt,
17463  Vector<Vector<Vector<unsigned> > > &global_node_names,
17464  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
17465  Vector<Node*> &global_shared_node_pt)
17466  {
17467  // Get the rank and number of processors
17468  const unsigned nproc = this->communicator_pt()->nproc();
17469  const unsigned my_rank = this->communicator_pt()->my_rank();
17470 
17471  // ---------------------------------------------------------------
17472  // BEGIN: Create a map to check whether a node is on the global
17473  // shared nodes. Also set a map to obtain the global
17474  // shared node index (this index is the same as the global
17475  // node name)
17476  // ---------------------------------------------------------------
17477  std::map<Node*, bool> is_global_shared_node;
17478  std::map<Node*, unsigned> global_shared_node_index;
17479 
17480  // Get the number of global shared nodes
17481  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17482  // loop over the global shared nodes
17483  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17484  {
17485  // Get the node
17486  Node* node_pt = global_shared_node_pt[i];
17487  // Indicate this is a shared global node
17488  is_global_shared_node[node_pt] = true;
17489  // Set the map to obtain the index of the global shared node
17490  global_shared_node_index[node_pt] = i;
17491 
17492  } // for (i < n_global_shared_nodes)
17493 
17494  // ---------------------------------------------------------------
17495  // END: Create a map to check whether a node is on the global
17496  // shared nodes. Also set a map to obtain the global
17497  // shared node index (this index is the same as the global
17498  // node name)
17499  // ---------------------------------------------------------------
17500 
17501  // ---------------------------------------------------------------
17502  // BEGIN: Loop over the haloed elements and check whether the nodes
17503  // on the haloed elements are part of the global shared
17504  // nodes. If that is the case then check whether the
17505  // element should be sent to the processors with which the
17506  // node is shared
17507  // ---------------------------------------------------------------
17508 
17509  // Elements that may be sent to other processors
17510  Vector<std::set<GeneralisedElement*> > additional_elements_pt(nproc);
17511 
17512  // loop over the processors
17513  for (unsigned iproc = 0; iproc < nproc; iproc++)
17514  {
17515  if (iproc!=my_rank)
17516  {
17517  // Get the haloed element with iproc
17518  Vector<GeneralisedElement*> haloed_ele_pt =
17519  this->root_haloed_element_pt(iproc);
17520 
17521  // Get the number of haloed elements
17522  const unsigned n_haloed_ele =
17523  this->nroot_haloed_element(iproc);
17524 
17525  // loop over the haloed elements with iproc
17526  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17527  {
17528  // A pointer to the generalised element
17529  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17530  // Get the finite element representation of the element
17531  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17532  // Get the number of nodes
17533  const unsigned n_nodes = ele_pt->nnode();
17534  // loop over the nodes of the element
17535  for (unsigned n = 0; n < n_nodes; n++)
17536  {
17537  // Get the node
17538  Node* node_pt = ele_pt->node_pt(n);
17539  // Is the node a global shared node?
17540  if (is_global_shared_node[node_pt])
17541  {
17542  // Get the index of the global shared node
17543  const unsigned global_index = global_shared_node_index[node_pt];
17544  // Get the global names of the node
17545  Vector<Vector<unsigned> > iglobal_names =
17546  global_node_names[global_index];
17547 
17548  // Get the number of names
17549  const unsigned n_names = iglobal_names.size();
17550  // loop over the names and check which processors share
17551  // this node (the processors to which the element may be
17552  // sent
17553  for (unsigned j = 0; j < n_names; j++)
17554  {
17555  // Get the processors to which the element should be
17556  // sent
17557  const unsigned proc1 = iglobal_names[j][0];
17558  const unsigned proc2 = iglobal_names[j][1];
17559  // Add the element to the set of additional elements to
17560  // sent from proc1 to proc2
17561  additional_elements_pt[proc1].insert(gele_pt);
17562  additional_elements_pt[proc2].insert(gele_pt);
17563 
17564  } // for (j < n_names)
17565 
17566  } // if (is_global_shared_node[node_pt])
17567 
17568  } // for (n < n_nodes)
17569 
17570  } // for (ihd < n_haloed_ele)
17571 
17572  } // if (iproc!=my_rank)
17573 
17574  } // for (iproc < nproc)
17575 
17576  // ---------------------------------------------------------------
17577  // Now check whether the element should really be sent to the
17578  // indicated processors
17579 
17580  // The elements from this (my_rank) processor that will be sent to
17581  // other processors
17582  Vector<Vector<FiniteElement*> > send_haloed_ele_pt(nproc);
17583 
17584  // loop over the processors
17585  for (unsigned iproc = 0; iproc < nproc; iproc++)
17586  {
17587  if (iproc!=my_rank)
17588  {
17589  // Get the set of element that may be sent to the iproc
17590  // processor
17591  std::set<GeneralisedElement*> iproc_ele_pt =
17592  additional_elements_pt[iproc];
17593  // loop over the element that may be sent to the iproc
17594  // processor
17595  for (std::set<GeneralisedElement*>::iterator it =
17596  iproc_ele_pt.begin(); it!=iproc_ele_pt.end(); it++)
17597  {
17598  // Get a pointer to the element
17599  GeneralisedElement* gele_pt = (*it);
17600 
17601  // Get the haloed element with iproc
17602  Vector<GeneralisedElement*> haloed_ele_pt =
17603  this->root_haloed_element_pt(iproc);
17604 
17605  // Get the number of haloed elements
17606  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17607 
17608  // Flag to indicate whether the element has been already sent
17609  // to the iproc processor
17610  bool send_ele_to_iproc_processor = true;
17611  // loop over the haloed elements with iproc and check whether
17612  // the element has been already sent to iproc (if it is
17613  // already a haloed element with iproc then it has been
17614  // already sent)
17615  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17616  {
17617  // A pointer to the generalised element
17618  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17619  if (gele_pt == ghd_ele_pt)
17620  {
17621  // Mark the element as not required to be sent
17622  send_ele_to_iproc_processor = false;
17623  // Break the loop that searchs for the element on the
17624  // haloed elements with iproc
17625  break;
17626  }
17627 
17628  } // for (ihd < n_haloed_ele)
17629 
17630  // Do we need to sent the element?
17631  if (send_ele_to_iproc_processor)
17632  {
17633  // Get the finite element representation of the element
17634  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17635  // Add the element to those that will be sent to the iproc
17636  // processor
17637  send_haloed_ele_pt[iproc].push_back(ele_pt);
17638  }
17639 
17640  } // loop over the elements that may be sent to the iproc
17641  // processor
17642 
17643  } // if (iproc!=my_rank)
17644 
17645  } // for (iproc < nproc)
17646 
17647  // ---------------------------------------------------------------
17648  // END: Loop over the haloed element and check whether the nodes
17649  // on the haloed elements are part of the global shared
17650  // nodes. If that is the case then check whether the element
17651  // should be sent to the processors with which the node is
17652  // shared
17653  // ---------------------------------------------------------------
17654 
17655  // ============================================================
17656  // Now send the additional elements
17657  // ============================================================
17658  // Loop over the processors to send data
17659  for (unsigned iproc = 0; iproc < nproc; iproc++)
17660  {
17661  // There are no elements to send with myself
17662  if (iproc != my_rank)
17663  {
17664  // Get the number of additional haloed elements to send
17665  const unsigned n_additional_haloed_ele =
17666  send_haloed_ele_pt[iproc].size();
17667 
17668  // Clear send and receive buffers
17669  Flat_packed_unsigneds.clear();
17670  Flat_packed_doubles.clear();
17671 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17672  Flat_packed_unsigneds_string.clear();
17673 #endif
17674 
17675  // The very first data of the flat packed is the number of
17676  // additional haloed elements, this will be the number of
17677  // additional halo elements to create on the receiver processor
17678  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17679 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17680  std::stringstream junk;
17681  junk << "Number of haloed elements " << nhaloed_ele;
17682  Flat_packed_unsigneds_string.push_back(junk.str());
17683 #endif
17684 
17685  // Loop over the additioanl haloed elements
17686  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17687  {
17688  // Get pointer to the additional haloed element
17689  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17690  const unsigned nroot_haloed_ele =
17691  this->nroot_haloed_element(iproc);
17692 
17693  // Check if the element has been already added to the
17694  // halo(ed) scheme
17695 
17696  // Get the generalised version of the element
17697  GeneralisedElement *gen_ele_pt = ele_pt;
17698  // Try to add the haloed element
17699  const unsigned haloed_ele_index =
17700  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17701 
17702  // Was the element added or only returned the index of the
17703  // element
17704  if (nroot_haloed_ele == haloed_ele_index)
17705  {
17706  Flat_packed_unsigneds.push_back(1);
17707 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17708  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
17709 #endif
17710 
17711  // Get additional info. related with the haloed element
17712  get_required_elemental_information_helper(iproc, ele_pt);
17713 
17714  // Get the nodes on the element
17715  const unsigned nnodes = ele_pt->nnode();
17716  for (unsigned j = 0; j < nnodes; j++)
17717  {
17718  Node* node_pt = ele_pt->node_pt(j);
17719 
17720  // Package the info. of the nodes
17721  // The destination processor goes in the arguments
17722  add_haloed_node_helper(iproc, node_pt);
17723 
17724  } // for (j < nnodes)
17725 
17726  } // add the element and send its nodes
17727  else // The haloed element already exists
17728  {
17729  Flat_packed_unsigneds.push_back(0);
17730 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17731  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
17732 #endif
17733  Flat_packed_unsigneds.push_back(haloed_ele_index);
17734 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17735  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
17736 #endif
17737  } // else (next_haloed_ele == external_haloed_ele_index)
17738 
17739  } // for (e < n_additional_haloed_ele)
17740 
17741  // Send and received the additional haloed elements (all
17742  // processors send and receive)
17743 
17744  // The processor to which send the elements
17745  int send_proc = static_cast<int>(iproc);
17746  // The processor from which receive the elements
17747  int recv_proc = static_cast<int>(iproc);
17748  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17749 
17750  // Reset the counters
17751  Counter_for_flat_packed_doubles=0;
17752  Counter_for_flat_packed_unsigneds=0;
17753 
17754  // Get the number of additional halo element to be created
17755  const unsigned n_additional_halo_ele =
17756  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
17757 
17758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17759  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
17760  << " Number of elements need to be constructed "
17761  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
17762  << std::endl;
17763 #endif
17764 
17765  // Create the additional halo elements
17766  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17767  {
17768  // Create halo element from received info. of "iproc"
17769  // processor on the current processor
17770  create_halo_element(iproc,
17771  iproc_currently_created_nodes_pt[iproc],
17772  other_proc_shd_bnd_node_pt,
17773  global_node_names,
17774  node_name_to_global_index,
17775  global_shared_node_pt);
17776 
17777  } // for (e < n_additional_halo_ele)
17778 
17779  } // if (iproc != my_rank)
17780 
17781  } // for (iproc < nproc)
17782 
17783  }
17784 
17785  // *********************************************************************
17786  // Start communication functions
17787  // *********************************************************************
17788 
17789  //========start of get_required_elemental_information_helper==============
17790  /// \short Helper function to get the required elemental information from
17791  /// an haloed element. This info. involves the association of the element
17792  /// to a boundary or region.
17793  //========================================================================
17794  template<class ELEMENT>
17797  FiniteElement* ele_pt)
17798  {
17799  // Check if the element is associated with the original boundaries
17800  const unsigned nbound = this->initial_shared_boundary_id();
17801 
17802  // ------------------------------------------------------------------
17803  // Stores the information regarding the boundaries associated to the
17804  // element (it that is the case)
17805  Vector<unsigned> associated_boundaries;
17806  Vector<unsigned> face_index_on_boundary;
17807 
17808  unsigned counter_face_indexes = 0;
17809 
17810  for (unsigned b = 0; b < nbound; b++)
17811  {
17812  // Get the number of elements associated to boundary i
17813  const unsigned nboundary_ele = nboundary_element(b);
17814  for (unsigned e = 0; e < nboundary_ele; e++)
17815  {
17816  if (ele_pt == this->boundary_element_pt(b,e))
17817  {
17818  // Keep track of the boundaries associated to the element
17819  associated_boundaries.push_back(b);
17820  // Get the face index
17821  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
17822  counter_face_indexes++;
17823 #ifdef PARANOID
17824  if (counter_face_indexes > 2)
17825  {
17826  std::stringstream error_message;
17827  error_message
17828  << "A triangular element can not have more than two of its faces "
17829  << "on a boundary!!!\n\n";
17830  throw OomphLibError(error_message.str(),
17831  OOMPH_CURRENT_FUNCTION,
17832  OOMPH_EXCEPTION_LOCATION);
17833  }
17834 #else
17835  // Already found 2 face indexes on the same boundary?
17836  if (counter_face_indexes==2) {break;}
17837 #endif // #ifdef PARANOID
17838 
17839  } // if (ele_pt == this->boundary_element_pt(b,e))
17840 
17841  } // (e < nboundary_ele)
17842 
17843  } // (b < nbound)
17844 
17845  // If the element is associated to any boundary then package all the
17846  // relevant info
17847  const unsigned nassociated_boundaries = associated_boundaries.size();
17848  if (nassociated_boundaries > 0)
17849  {
17850  Flat_packed_unsigneds.push_back(1);
17851 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17852  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
17853 #endif
17854  Flat_packed_unsigneds.push_back(nassociated_boundaries);
17855 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17856  std::stringstream junk;
17857  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
17858  Flat_packed_unsigneds_string.push_back(junk.str());
17859 #endif
17860 
17861  // Package the ids of the associated boundaries and the
17862  // corresponding face index for each boundary (if the element is a
17863  // corner element, it will have two faces associated to the
17864  // boundary)
17865  for (unsigned i = 0; i < nassociated_boundaries; i++)
17866  {
17867  unsigned b = associated_boundaries[i];
17868  Flat_packed_unsigneds.push_back(b);
17869 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17870  std::stringstream junk;
17871  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
17872  Flat_packed_unsigneds_string.push_back(junk.str());
17873 #endif
17874  unsigned f = face_index_on_boundary[i];
17875  Flat_packed_unsigneds.push_back(f);
17876 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17877  std::stringstream junk2;
17878  junk2 << "Face index " << f << " for associated boundary " << b;
17879  Flat_packed_unsigneds_string.push_back(junk2.str());
17880 #endif
17881  }
17882 
17883  // If the element is associated to any boundary then we should
17884  // check if the mesh has regions, if that is the case then we need
17885  // to check to which region the boundary element does belong
17886 
17887  // If the mesh has regions we should look for the element
17888  // associated to a boundary and a specified region
17889  Vector<Vector<unsigned> > associated_boundaries_and_regions;
17890  Vector<unsigned> face_index_on_boundary_and_region;
17891 
17892  // Now check for the case when we have regions in the mesh
17893  const unsigned n_regions = this->nregion();
17894  if (n_regions > 1)
17895  {
17896  // Used to count the number of faces associated with
17897  // boundary-regions
17898  unsigned counter_face_indexes_in_regions = 0;
17899  // Loop over the boundaries
17900  for (unsigned b = 0; b < nbound; b++)
17901  {
17902  // Go through each region by getting the region id
17903  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
17904  {
17905  // Get thre region id associated with the (i_reg)-th region
17906  const unsigned region_id =
17907  static_cast<unsigned>(this->Region_attribute[i_reg]);
17908 
17909  // Loop over all elements associated with the current boundary
17910  // and the i_reg-th region and check if the element is part of
17911  // any region
17912  const unsigned nele_in_region =
17913  this->nboundary_element_in_region(b, region_id);
17914  for (unsigned ee = 0; ee < nele_in_region; ee++)
17915  {
17916  // Check if the boundary-region element is the same as the
17917  // element
17918  if (ele_pt ==
17919  this->boundary_element_in_region_pt(b, region_id, ee))
17920  {
17921  // Storage for the boundary and region associated to the
17922  // element
17923  Vector<unsigned> bound_and_region(2);
17924 
17925  // Keep track of the boundaries associated to the element
17926  bound_and_region[0] = b;
17927  // Keep track of the regions associated to the element
17928  bound_and_region[1] = region_id;
17929  // Add the boundaries and regions in the storage to be
17930  // sent to other processors
17931  associated_boundaries_and_regions.push_back(bound_and_region);
17932  // Get the face index and keep track of it
17933  face_index_on_boundary_and_region.push_back(
17934  this->face_index_at_boundary_in_region(b,region_id,ee));
17935 
17936  // Increase the number of faces of the element associated
17937  // to boundary-regions
17938  counter_face_indexes_in_regions++;
17939 
17940 #ifdef PARANOID
17941  if (counter_face_indexes_in_regions > 2)
17942  {
17943  std::stringstream error_message;
17944  error_message
17945  << "A triangular element can not have more than two of its\n"
17946  << "faces on a boundary!!!\n\n";
17947  throw OomphLibError(error_message.str(),
17948  OOMPH_CURRENT_FUNCTION,
17949  OOMPH_EXCEPTION_LOCATION);
17950  } // if (counter_face_indexes_in_regions > 2)
17951 #endif
17952 
17953  } // The element is a boundary-region element
17954 
17955  } // for (ee < nele_in_region)
17956 
17957  } // for (i_reg < n_regions)
17958 
17959  } // for (b < nbound)
17960 
17961  } // if (n_regions > 1)
17962 
17963  // Now package the info. to be sent to other processors
17964  const unsigned nassociated_boundaries_and_regions =
17965  associated_boundaries_and_regions.size();
17966  if (nassociated_boundaries_and_regions > 0)
17967  {
17968  Flat_packed_unsigneds.push_back(1);
17969 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17970  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
17971 #endif
17972 
17973  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
17974 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17975  std::stringstream junk;
17976  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
17977  Flat_packed_unsigneds_string.push_back(junk.str());
17978 #endif
17979 
17980  // Package the ids of the associated boundaries, regions and the
17981  // corresponding face index for each boundary-region (if the
17982  // element is a corner element, it will have two faces
17983  // associated to the boundary-region)
17984  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
17985  {
17986  const unsigned b = associated_boundaries_and_regions[i][0];
17987  Flat_packed_unsigneds.push_back(b);
17988 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17989  std::stringstream junk;
17990  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17991  Flat_packed_unsigneds_string.push_back(junk.str());
17992 #endif
17993 
17994  const unsigned r = associated_boundaries_and_regions[i][1];
17995  Flat_packed_unsigneds.push_back(r);
17996 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17997  std::stringstream junk2;
17998  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17999  Flat_packed_unsigneds_string.push_back(junk2.str());
18000 #endif
18001 
18002  const unsigned f = face_index_on_boundary_and_region[i];
18003  Flat_packed_unsigneds.push_back(f);
18004 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18005  std::stringstream junk3;
18006  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
18007  Flat_packed_unsigneds_string.push_back(junk3.str());
18008 #endif
18009  } // for (i < nassociated_boundaries_and_regions)
18010  } // if (nassociated_boundaries_and_regions > 0)
18011  else
18012  {
18013  Flat_packed_unsigneds.push_back(0);
18014 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18015  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
18016 #endif
18017  } // else if (nassociated_boundaries_and_regions > 0)
18018 
18019  }
18020  else
18021  {
18022  Flat_packed_unsigneds.push_back(0);
18023 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18024  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
18025 #endif
18026  }
18027 
18028  // ------------------------------------------------------------
18029  // Now review if the element is associated to a shared boundary
18030 
18031  // Store the shared boundaries, and therefore the face indexes
18032  // associated to the element
18033  Vector<unsigned> associated_shared_boundaries;
18034  Vector<unsigned> face_index_on_shared_boundary;
18035 
18036  // Get the shared boundaries in this processor
18037  Vector<unsigned> my_rank_shared_boundaries_ids;
18038  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18039 
18040  // Get the number of shared boundaries
18041  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18042  // Loop over the shared boundaries
18043  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18044  {
18045  // Get the boundary id
18046  const unsigned sb = my_rank_shared_boundaries_ids[i];
18047 
18048  // Get the number of elements associated to shared boundary sb
18049  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18050  for (unsigned e = 0; e < nboundary_ele; e++)
18051  {
18052  if (ele_pt == this->shared_boundary_element_pt(sb,e))
18053  {
18054  // Keep track of the boundaries associated to the element
18055  associated_shared_boundaries.push_back(sb);
18056  // Get the face index
18057  face_index_on_shared_boundary.push_back(
18058  this->face_index_at_shared_boundary(sb, e));
18059  }
18060  } // (e < nboundary_ele)
18061  } // (i < nmy_rank_shd_bnd)
18062 
18063  // If the element is associated to a shared boundary then package
18064  // all the relevant info
18065  const unsigned nassociated_shared_boundaries =
18066  associated_shared_boundaries.size();
18067  if (nassociated_shared_boundaries > 0)
18068  {
18069  Flat_packed_unsigneds.push_back(3);
18070 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18071  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
18072 #endif
18073  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18074 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18075  std::stringstream junk;
18076  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
18077  Flat_packed_unsigneds_string.push_back(junk.str());
18078 #endif
18079 
18080  // Package the ids of the associated boundaries
18081  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18082  {
18083  const unsigned b = associated_shared_boundaries[i];
18084  Flat_packed_unsigneds.push_back(b);
18085 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18086  std::stringstream junk;
18087  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
18088  Flat_packed_unsigneds_string.push_back(junk.str());
18089 #endif
18090 
18091  const unsigned f = face_index_on_shared_boundary[i];
18092  Flat_packed_unsigneds.push_back(f);
18093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18094  std::stringstream junk2;
18095  junk2 << "Face index " << f << " for associated shared boundary " << b;
18096  Flat_packed_unsigneds_string.push_back(junk2.str());
18097 #endif
18098  }
18099  }
18100  else
18101  {
18102  Flat_packed_unsigneds.push_back(0);
18103 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18104  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
18105 #endif
18106  }
18107 
18108  }
18109 
18110  //========start of get_required_nodal_information_helper==================
18111  /// Helper function to get the required nodal information from an
18112  /// haloed node so that a fully-functional halo node (and therefore element)
18113  /// can be created on the receiving process
18114  //========================================================================
18115  template<class ELEMENT>
18118  Node* nod_pt)
18119  {
18120  unsigned my_rank = this->communicator_pt()->my_rank();
18121  const unsigned nproc = this->communicator_pt()->nproc();
18122 
18123  // Tell the halo copy of this node how many values there are
18124  // [NB this may be different for nodes within the same element, e.g.
18125  // when using Lagrange multipliers]
18126  unsigned n_val=nod_pt->nvalue();
18127  Flat_packed_unsigneds.push_back(n_val);
18128 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18129  Flat_packed_unsigneds_string.push_back("Number of values");
18130 #endif
18131 
18132  unsigned n_dim=nod_pt->ndim();
18133 
18134  // Default number of previous values to 1
18135  unsigned n_prev=1;
18136  if (this->Time_stepper_pt!=0)
18137  {
18138  // Add number of history values to n_prev
18139  n_prev=this->Time_stepper_pt->ntstorage();
18140  }
18141 
18142  // -----------------------------------------------------
18143  // Is the node on an original boundary?
18144  // Store the original boundaries where the node may be
18145  Vector<unsigned> original_boundaries;
18146  // Loop over the original boundaries of the mesh and check if live
18147  // on one of them
18148  const unsigned n_bnd = this->initial_shared_boundary_id();
18149  for (unsigned bb=0;bb<n_bnd;bb++)
18150  {
18151  // Which boundaries (could be more than one) is it on?
18152  if (nod_pt->is_on_boundary(bb))
18153  {
18154  original_boundaries.push_back(bb);
18155  }
18156 
18157  }
18158 
18159  const unsigned n_original_boundaries = original_boundaries.size();
18160  // Is the node on any original boundary?
18161  if (n_original_boundaries > 0)
18162  {
18163  // Indicate that the node is on an original boundary
18164  Flat_packed_unsigneds.push_back(2);
18165 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18166  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
18167 #endif
18168 
18169  Flat_packed_unsigneds.push_back(n_original_boundaries);
18170 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18171  std::stringstream junk;
18172  junk << "Node is on "<< n_original_boundaries << " original boundaries";
18173  Flat_packed_unsigneds_string.push_back(junk.str());
18174 #endif
18175 
18176  // Loop over the original boundaries the node is on
18177  for (unsigned i=0;i<n_original_boundaries;i++)
18178  {
18179  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18180 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18181  std::stringstream junk;
18182  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
18183  Flat_packed_unsigneds_string.push_back(junk.str());
18184 #endif
18185  // Get the boundary coordinate of the node
18186  Vector<double> zeta(1);
18187  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
18188  Flat_packed_doubles.push_back(zeta[0]);
18189  }
18190  }
18191  else
18192  {
18193  // Indicate that the node is NOT on an original boundary
18194  Flat_packed_unsigneds.push_back(0);
18195 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18196  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
18197 #endif
18198  }
18199 
18200  // -------------------------------------------------------
18201  // Is the node on shared boundaries?
18202  bool node_on_shared_boundary = false;
18203  // Loop over the shared boundaries with the iproc processors and
18204  // check if live on one of them
18205  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18206  for (unsigned bb=0;bb<n_shd_bnd;bb++)
18207  {
18208  // Get the boundary id
18209  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18210  // Which boundaries (could be more than one) is it on?
18211  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18212  {
18213  node_on_shared_boundary = true;
18214  break;
18215  }
18216  }
18217 
18218  // If the node live on any of the shared boundaries with the iproc
18219  // processor then just get the node number according to the
18220  // sorted_shared_boundary_node_pt() scheme and send it accross
18221  if (node_on_shared_boundary)
18222  {
18223  Flat_packed_unsigneds.push_back(1);
18224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18225  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18226 #endif
18227 
18228  // Store the shared boundaries where the node is on
18229  Vector<unsigned> shd_boundaries;
18230  // Loop over the shared boundaries with the iproc processor
18231  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18232  {
18233  // Get the boundary id
18234  const unsigned i_bnd =
18235  this->shared_boundaries_ids(my_rank, iproc, bb);
18236  // Which boundaries (could be more than one) is it on?
18237  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18238  {
18239  shd_boundaries.push_back(i_bnd);
18240  }
18241  }
18242 
18243  // Get the number of shared boundaries the node is on
18244  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18245  // Send the number of shared boundaries the node is on
18246  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18247 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18248  std::stringstream junk;
18249  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
18250  Flat_packed_unsigneds_string.push_back(junk.str());
18251 #endif
18252 
18253  // Loop over the shared boundaries to send their ids
18254  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
18255  {
18256  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18257 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18258  std::stringstream junk;
18259  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18260  Flat_packed_unsigneds_string.push_back(junk.str());
18261 #endif
18262  }
18263 
18264  // Given that the node is on at least one boundary get the index
18265  // of the node in one of the boundaries and send this index
18266  unsigned shared_boundary_id = shd_boundaries[0];
18267  // Get the number of nodes on the given shared boundary
18268  const unsigned n_nodes_on_shared_boundary =
18269  nsorted_shared_boundary_node(shared_boundary_id);
18270  // Store the index of the node on the shared boundary
18271  unsigned index_node_on_shared_boundary;
18272 #ifdef PARANOID
18273  // Flag to know if the node has been found
18274  bool found_index_node_on_shared_boundary = false;
18275 #endif
18276  // Loop over the nodes on the shared boundary to find the node
18277  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18278  {
18279  // Get the i-th node on the shared boundary
18280  Node* shared_node_pt =
18281  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18282  // Is the node we are looking for
18283  if (shared_node_pt == nod_pt)
18284  {
18285  // Store the index
18286  index_node_on_shared_boundary = i;
18287 #ifdef PARANOID
18288  // Mark as found
18289  found_index_node_on_shared_boundary = true;
18290 #endif
18291  break; // break
18292  }
18293 
18294  } // for (i < nnodes_on_shared_boundary)
18295 
18296 #ifdef PARANOID
18297  if (!found_index_node_on_shared_boundary)
18298  {
18299  std::ostringstream error_message;
18300  error_message
18301  <<"The index of the node on boundary ("
18302  <<shared_boundary_id<<") was not found.\n"
18303  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18304  <<nod_pt->x(1)<<").\n";
18305  throw OomphLibError(
18306  error_message.str(),
18307  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18308  OOMPH_EXCEPTION_LOCATION);
18309  }
18310 #endif
18311  // Send the index of the node on the shared boundary
18312  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18314  std::stringstream junk2;
18315  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
18316  <<index_node_on_shared_boundary;
18317  Flat_packed_unsigneds_string.push_back(junk2.str());
18318 #endif
18319 
18320  } // if (node_on_shared_boundary)
18321  else
18322  {
18323  // The node is not on a shared boundary
18324  Flat_packed_unsigneds.push_back(0);
18325 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18326  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
18327 #endif
18328  }
18329 
18330  // ----------------------------------------------------------------
18331  // Is the node on any shared boundary where the receiver processor
18332  // is not involved?
18333 
18334  // Now check if the node is on a shared boundary created by the
18335  // current processor (my_rank) and other processor different that
18336  // the iproc processor. This info. will help to complete the sending
18337  // of halo(ed) information between processors
18338 
18339  // Flag to know if the node is on a shared boundary with other
18340  // processor
18341  bool node_on_shared_boundary_with_other_processors = false;
18342  // Count the number of other shared boundaries it could be on
18343  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18344 
18345  // Loop over the shared boundaries of the sent processor (my_rank)
18346  // and other processors (jproc)
18347  for (unsigned jproc = 0; jproc < nproc; jproc++)
18348  {
18349  // Do not search with the iproc processor , that was done before
18350  // above because we are sending info to that processor
18351  if (jproc != iproc)
18352  {
18353  // Get the number of shared boundaries with the jproc processor
18354  const unsigned n_jshd_bnd =
18355  this->nshared_boundaries(my_rank, jproc);
18356  // Loop over the shared boundaries
18357  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
18358  {
18359  // Get the boundary id
18360  const unsigned j_shd_bnd =
18361  this->shared_boundaries_ids(my_rank, jproc, bb);
18362  // Is the node part of this boundary?
18363  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18364  {
18365 // DEBP("Sending to");
18366 // DEBP(iproc);
18367 // DEBP("Pair of procs where other shared");
18368 // DEBP(my_rank);
18369 // DEBP(jproc);
18370 // DEBP(i_bnd);
18371  node_on_shared_boundary_with_other_processors = true;
18372  // Increase the counter for the number of shared boundaries
18373  // with other processors the node is on
18374  nshared_boundaries_with_other_processors_have_node++;
18375  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18376 
18377  } // for (bb<n_jshd_bnd)
18378 
18379  } // if (jproc != iproc)
18380 
18381  } // for (jproc < nproc)
18382 
18383  // If the node is on a shared boundary with another processor
18384  // (my_rank, jproc), then send the flag and look for the info.
18385  if (node_on_shared_boundary_with_other_processors)
18386  {
18387  Flat_packed_unsigneds.push_back(4);
18388 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18389  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
18390 #endif
18391 
18392  // The number of packages of information that will be sent to the
18393  // "iproc" processor. This helps to know how many packages of data
18394  // read from the received processor
18395  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
18396 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18397  std::stringstream junk;
18398  junk << "Number of other shared boundaries that the node is on: "
18399  << nshared_boundaries_with_other_processors_have_node;
18400  Flat_packed_unsigneds_string.push_back(junk.str());
18401 #endif
18402 
18403  // Counter to ensure that the correct number of data has been sent
18404  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18405  // Loop over the shared boundaries with other processors and get:
18406  // 1) The processors defining the shared boundary
18407  // 2) The shared boundary id
18408  // 3) The index of the node on the shared boundary
18409  Vector<unsigned> other_processor_1;
18410  Vector<unsigned> other_processor_2;
18411  Vector<unsigned> shd_bnd_ids;
18412  Vector<unsigned> indexes;
18413  // Loop over the processors again
18414  for (unsigned jproc = 0; jproc < nproc; jproc++)
18415  {
18416  // Do not search with the iproc processor, that was done before
18417  // above
18418  if (jproc != iproc)
18419  {
18420  // Get the number of shared boundaries with the jproc
18421  // processor
18422  const unsigned n_jshd_bnd =
18423  this->nshared_boundaries(my_rank, jproc);
18424  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18425  {
18426  // Get the boundary id
18427  const unsigned j_shd_bnd =
18428  this->shared_boundaries_ids(my_rank, jproc, bb);
18429  // Is the node part of this boundary?
18430  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18431  {
18432  // Include the first processor
18433  other_processor_1.push_back(my_rank);
18434  // Include the second processor
18435  other_processor_2.push_back(jproc);
18436  // Include the shared boundary id
18437  shd_bnd_ids.push_back(j_shd_bnd);
18438  // Increase the counter for found shared boundaries with
18439  // other processors
18440  counter_shd_bnd_with_other_procs_have_node++;
18441  }
18442 
18443  } // for (bb < nshared_bnd)
18444 
18445  } // if (jproc != iproc)
18446 
18447  } // for (jproc < nproc)
18448 
18449  // Get the indexes of the node on all the shared boundaries where
18450  // it was found
18451  const unsigned n_other_processors = other_processor_1.size();
18452  // Loop over the processors where the node was found
18453  for (unsigned i = 0; i < n_other_processors; i++)
18454  {
18455  // Get the shared boundary id
18456  unsigned shd_bnd_id = shd_bnd_ids[i];
18457  // Get the number of nodes on that shared boundary
18458  const unsigned n_nodes_on_shd_bnd =
18459  nsorted_shared_boundary_node(shd_bnd_id);
18460 
18461 #ifdef PARANOID
18462  bool found_index_node_on_shared_boundary = false;
18463 #endif
18464  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18465  {
18466  // Get the i-th shared boundary node
18467  Node* shared_node_pt =
18468  sorted_shared_boundary_node_pt(shd_bnd_id, i);
18469  // Is the same node?
18470  if (shared_node_pt == nod_pt)
18471  {
18472 // DEBP(i_node);
18473 // DEBP(nod_pt->x(0));
18474 // DEBP(nod_pt->x(1));
18475  // Include the index of the node
18476  indexes.push_back(i);
18477 #ifdef PARANOID
18478  // Mark as found the node
18479  found_index_node_on_shared_boundary = true;
18480 #endif
18481  break;
18482  } // if (shared_node_pt == nod_pt)
18483 
18484  } // for (i < n_nodes_on_shd_bnd)
18485 
18486 #ifdef PARANOID
18487  if (!found_index_node_on_shared_boundary)
18488  {
18489  std::ostringstream error_message;
18490  error_message
18491  <<"The index of the node on boundary ("
18492  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
18493  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18494  <<nod_pt->x(1)<<").\n";
18495  throw OomphLibError(
18496  error_message.str(),
18497  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18498  OOMPH_EXCEPTION_LOCATION);
18499  }
18500 #endif
18501  } // for (i < n_other_processors)
18502 
18503  // Now send the info. but first check that the number of found
18504  // nodes be the same that the previously found shared boundaries
18505  // with the node
18506 #ifdef PARANOID
18507  if (counter_shd_bnd_with_other_procs_have_node !=
18508  nshared_boundaries_with_other_processors_have_node)
18509  {
18510  std::ostringstream error_message;
18511  error_message
18512  <<"The number of shared boundaries where the node is on "
18513  <<"is different:\n"
18514  << "nshared_boundaries_with_other_processors_have_node: ("
18515  << nshared_boundaries_with_other_processors_have_node
18516  << ")\n"
18517  << "counter_shd_bnd_with_other_procs_have_node: ("
18518  << counter_shd_bnd_with_other_procs_have_node
18519  << ")\n";
18520  throw OomphLibError(
18521  error_message.str(),
18522  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18523  OOMPH_EXCEPTION_LOCATION);
18524  } // if (counter_shd_bnd_with_other_procs_have_node !=
18525  // nshared_boundaries_with_other_processors_have_node)
18526 #endif
18527 
18528  // Loop over the info. to send it
18529  for (unsigned i = 0; i < n_other_processors; i++)
18530  {
18531  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18532 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18533  std::stringstream junk1;
18534  junk1 << "Processor where the other shared boundary "
18535  << "has the node: " << other_processor_1[i];
18536  Flat_packed_unsigneds_string.push_back(junk1.str());
18537 #endif
18538 
18539  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18540 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18541  std::stringstream junk2;
18542  junk2 << "Processor where the other shared boundary "
18543  << "has the node: " << other_processor_2[i];
18544  Flat_packed_unsigneds_string.push_back(junk2.str());
18545 #endif
18546 
18547  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18548 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18549  std::stringstream junk3;
18550  junk3 << "Other shared boundary id where the node is on"
18551  << boundaries[i];
18552  Flat_packed_unsigneds_string.push_back(junk3.str());
18553 #endif
18554 
18555  Flat_packed_unsigneds.push_back(indexes[i]);
18556 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18557  std::stringstream junk4;
18558  junk4 << "Node index on other shared boundary "
18559  <<boundaries[i] << " is "
18560  << indexes[i];
18561  Flat_packed_unsigneds_string.push_back(junk4.str());
18562 #endif
18563 
18564  } // for (i < n_other_processors)
18565 
18566  } // if (node_on_shared_boundary_with_other_processors)
18567  else
18568  {
18569  Flat_packed_unsigneds.push_back(0);
18570 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18571  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
18572 #endif
18573  } // else if (node_on_shared_boundary_with_other_processors)
18574 
18575  // Now check if it is required to send the info. of the node. If the
18576  // node is not on a shared boundary with the iproc processor then we
18577  // need to send the info.
18578 
18579  if (!node_on_shared_boundary)
18580  {
18581  // Send all the info. to create it
18582 
18583  // Is the Node algebraic? If so, send its ref values and
18584  // an indication of its geometric objects if they are stored
18585  // in the algebraic mesh
18586  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
18587  if (alg_nod_pt!=0)
18588  {
18589  // The external mesh should be algebraic
18590  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
18591 
18592  // Get default node update function ID
18593  unsigned update_id=alg_nod_pt->node_update_fct_id();
18594  Flat_packed_unsigneds.push_back(update_id);
18595 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18596  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18597 #endif
18598 
18599  // Get reference values at default...
18600  unsigned n_ref_val=alg_nod_pt->nref_value();
18601  Flat_packed_unsigneds.push_back(n_ref_val);
18602 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18603  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18604 #endif
18605  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
18606  {
18607  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18608  }
18609 
18610  // Access geometric objects at default...
18611  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
18612  Flat_packed_unsigneds.push_back(n_geom_obj);
18613 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18614  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18615 #endif
18616  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
18617  {
18618  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
18619 
18620  // Check this against the stored geometric objects in mesh
18621  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
18622 
18623  // Default found index to zero
18624  unsigned found_geom_object=0;
18625  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
18626  {
18627  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
18628  {
18629  found_geom_object=i_list;
18630  }
18631  }
18632  Flat_packed_unsigneds.push_back(found_geom_object);
18633 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18634  Flat_packed_unsigneds_string.push_back("Found geom object");
18635 #endif
18636  }
18637  } // (if alg_nod_pt!=0)
18638 
18639  // Is it a SolidNode?
18640  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
18641  if (solid_nod_pt!=0)
18642  {
18643  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
18644  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
18645  {
18646  for (unsigned t=0;t<n_prev;t++)
18647  {
18648  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
18649  value(t,i_val));
18650  }
18651  }
18652 
18653  Vector<double> values_solid_node;
18654  solid_nod_pt->add_values_to_vector(values_solid_node);
18655  const unsigned nvalues_solid_node = values_solid_node.size();
18656  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18657 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18658  std::stringstream junk;
18659  junk << "Number of values solid node: "
18660  << nvalues_solid_node;
18661  Flat_packed_unsigneds_string.push_back(junk.str());
18662 #endif
18663  for (unsigned i = 0; i < nvalues_solid_node; i++)
18664  {
18665  Flat_packed_doubles.push_back(values_solid_node[i]);
18666  }
18667  }
18668 
18669  // Finally copy info required for all node types
18670  for (unsigned i_val=0;i_val<n_val;i_val++)
18671  {
18672  for (unsigned t=0;t<n_prev;t++)
18673  {
18674  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
18675  }
18676  }
18677 
18678  // Now do positions
18679  for (unsigned idim=0;idim<n_dim;idim++)
18680  {
18681  for (unsigned t=0;t<n_prev;t++)
18682  {
18683  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
18684  }
18685  }
18686 
18687  } // if (!node_on_shared_boundary)
18688 
18689  }
18690 
18691  //==========start of add_haloed_node_helper===============================
18692  /// Helper to add external haloed node that is not a master
18693  //========================================================================
18694  template<class ELEMENT>
18696  add_haloed_node_helper(unsigned& iproc, Node* nod_pt)
18697  {
18698  // Attempt to add this node as a haloed node
18699  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18700  const unsigned haloed_node_index =
18701  this->try_to_add_haloed_node_pt(iproc,nod_pt);
18702 
18703  // If it was added then the new index should match the size of the storage
18704  if (haloed_node_index==n_haloed_nod)
18705  {
18706  Flat_packed_unsigneds.push_back(1);
18707 
18708 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18709  std::stringstream junk;
18710  junk << "Node needs to be constructed [size="
18711  << Flat_packed_unsigneds.size() << "]; last entry: "
18712  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
18713  Flat_packed_unsigneds_string.push_back(junk.str());
18714 #endif
18715 
18716  // This helper function gets all the required information for the
18717  // specified node and stores it into MPI-sendable information
18718  // so that a halo copy can be made on the receiving process
18719  get_required_nodal_information_helper(iproc, nod_pt);
18720  }
18721  else // It was already added
18722  {
18723  Flat_packed_unsigneds.push_back(0);
18724 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18725  std::stringstream junk;
18726  junk << "Node was already added [size="
18727  << Flat_packed_unsigneds.size() << "]; last entry: "
18728  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
18729 
18730  Flat_packed_unsigneds_string.push_back(junk.str());
18731 #endif
18732 
18733  // This node is already a haloed node, so tell
18734  // the other process its index in the equivalent halo storage
18735  Flat_packed_unsigneds.push_back(haloed_node_index);
18736 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18737  Flat_packed_unsigneds_string.push_back("haloed node index");
18738 #endif
18739  }
18740 
18741  }
18742 
18743  //================= send_and_receive_haloed_info =======================
18744  /// Send the information of the elements that will be created on the other
18745  /// processor
18746  //======================================================================
18747  template<class ELEMENT>
18749  send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
18750  {
18751  // Get the communicator of the mesh
18752  OomphCommunicator* comm_pt = this->communicator_pt();
18753 
18754  // Set MPI info
18755  MPI_Status status;
18756  MPI_Request request;
18757 
18758  // Prepare vectors to receive information
18759  Vector<double> received_double_values;
18760  Vector<unsigned> received_unsigned_values;
18761 
18762  // Send the double values associated with halo(ed) elements and nodes
18763  //-------------------------------------------------------------------
18764  unsigned send_count_double_values=Flat_packed_doubles.size();
18765  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
18766  send_proc,1,comm_pt->mpi_comm(),&request);
18767 
18768  int receive_count_double_values=0;
18769  MPI_Recv(&receive_count_double_values,1,MPI_INT,
18770  recv_proc,1,comm_pt->mpi_comm(),&status);
18771  MPI_Wait(&request,MPI_STATUS_IGNORE);
18772 
18773  if (send_count_double_values!=0)
18774  {
18775  MPI_Isend(&Flat_packed_doubles[0],send_count_double_values,MPI_DOUBLE,
18776  send_proc,2,comm_pt->mpi_comm(),&request);
18777  }
18778  if (receive_count_double_values!=0)
18779  {
18780  received_double_values.resize(receive_count_double_values);
18781  MPI_Recv(&received_double_values[0],receive_count_double_values,
18782  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
18783  }
18784  if (send_count_double_values!=0)
18785  {
18786  MPI_Wait(&request,MPI_STATUS_IGNORE);
18787  }
18788 
18789  // Now send unsigned values associated with halo(ed) elements and nodes
18790  //---------------------------------------------------------------------
18791  unsigned send_count_unsigned_values=Flat_packed_unsigneds.size();
18792 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18793  unsigned send_count_unsigned_string=Flat_packed_unsigneds_string.size();
18794 #ifdef PARANOID
18795  if (send_count_unsigned_string != send_count_unsigned_values)
18796  {
18797  std::ostringstream error_message;
18798  error_message
18799  << "The number of unsigned values to send to processor ("
18800  << send_proc << ") is different from the\nnumber of annotated strings "
18801  << "for the communication\n\n";
18802  throw OomphLibError(error_message.str(),
18803  OOMPH_CURRENT_FUNCTION,
18804  OOMPH_EXCEPTION_LOCATION);
18805  }
18806 #endif // #ifdef PARANOID
18807 #endif
18808  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
18809  send_proc,14,comm_pt->mpi_comm(),&request);
18810 
18811  int receive_count_unsigned_values=0;
18812  MPI_Recv(&receive_count_unsigned_values,1,MPI_INT,recv_proc,14,
18813  comm_pt->mpi_comm(),&status);
18814 
18815  MPI_Wait(&request,MPI_STATUS_IGNORE);
18816 
18817  if (send_count_unsigned_values!=0)
18818  {
18819  MPI_Isend(&Flat_packed_unsigneds[0],send_count_unsigned_values,
18820  MPI_UNSIGNED,send_proc,15,comm_pt->mpi_comm(),&request);
18821 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18822  for (unsigned i=0;i<send_count_unsigned_values;i++)
18823  {
18824  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc
18825  << " " << Flat_packed_unsigneds_string[i]
18826  << ": " << Flat_packed_unsigneds[i] << std::endl;
18827  }
18828 #endif
18829  }
18830  if (receive_count_unsigned_values!=0)
18831  {
18832  received_unsigned_values.resize(receive_count_unsigned_values);
18833  MPI_Recv(&received_unsigned_values[0],receive_count_unsigned_values,
18834  MPI_UNSIGNED,recv_proc,15,comm_pt->mpi_comm(),&status);
18835  }
18836 
18837  if (send_count_unsigned_values!=0)
18838  {
18839  MPI_Wait(&request,MPI_STATUS_IGNORE);
18840  }
18841 
18842  // Copy across into original containers -- these can now
18843  //------------------------------------------------------
18844  // be processed by create_external_halo_elements() to generate
18845  //------------------------------------------------------------
18846  // external halo elements
18847  //------------------------
18848  Flat_packed_doubles.resize(receive_count_double_values);
18849  for (int ii=0;ii<receive_count_double_values;ii++)
18850  {
18851  Flat_packed_doubles[ii]=received_double_values[ii];
18852  }
18853  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
18854  for (int ii=0;ii<receive_count_unsigned_values;ii++)
18855  {
18856  Flat_packed_unsigneds[ii]=received_unsigned_values[ii];
18857  }
18858 
18859  }
18860 
18861  //=====================================================================
18862  /// Creates (halo) element on the loop process based on the
18863  /// information received from each processor
18864  //=====================================================================
18865  template<class ELEMENT>
18867  create_halo_element(unsigned& iproc,
18868  Vector<Node*> &new_nodes_on_domain,
18869  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
18870  &other_proc_shd_bnd_node_pt,
18871  Vector<Vector<Vector<unsigned> > >
18872  &global_node_names,
18873  std::map<Vector<unsigned>, unsigned>
18874  &node_name_to_global_index,
18875  Vector<Node*> &global_shared_node_pt)
18876  {
18877 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18878  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
18879  << " Bool: New element needs to be constructed "
18880  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18881  << std::endl;
18882 #endif
18883 
18884  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
18885  {
18886  // Create a new element from the communicated values
18887  // and coords from the process that located zeta
18888  GeneralisedElement *new_el_pt= new ELEMENT;
18889 
18890  // Add the element, it is a new element in the mesh
18891  this->add_element_pt(new_el_pt);
18892 
18893  // Add halo element to this mesh
18894  this->add_root_halo_element_pt(iproc, new_el_pt);
18895 
18896  // Cast to the FE pointer
18897  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
18898 
18899  // Check if new element is associated to any boundary
18900  this->add_halo_element_helper(iproc,f_el_pt);
18901 
18902  // Now we add nodes to the new element
18903  unsigned n_node=f_el_pt->nnode();
18904 
18905  for (unsigned j=0;j<n_node;j++)
18906  {
18907  Node* new_nod_pt=0;
18908 
18909  // Call the add halo node helper function
18910  add_halo_node_helper(new_nod_pt,
18911  new_nodes_on_domain,
18912  other_proc_shd_bnd_node_pt,
18913  iproc, j, f_el_pt,
18914  global_node_names,
18915  node_name_to_global_index,
18916  global_shared_node_pt);
18917 
18918  } // for (j<n_nod)
18919 
18920  }
18921  else // the element already exists as halo
18922  {
18923 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18924  oomph_info
18925  << "Rec:" << Counter_for_flat_packed_unsigneds
18926  << " Index of existing halo element "
18927  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18928  << std::endl;
18929 #endif
18930  // The index itself is in Flat_packed_unsigneds[...]
18931  unsigned halo_ele_index=
18932  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18933 
18934  // Use this index to get the element
18935  FiniteElement* f_el_pt=
18936  dynamic_cast<FiniteElement*>(this->root_halo_element_pt(iproc,
18937  halo_ele_index));
18938 
18939  //If it's not a finite element die
18940  if(f_el_pt==0)
18941  {
18942  throw OomphLibError("Halo element is not a FiniteElement\n",
18943  OOMPH_CURRENT_FUNCTION,
18944  OOMPH_EXCEPTION_LOCATION);
18945  }
18946 
18947  } // else the element already exists as halo
18948 
18949  }
18950 
18951  //========start of add_halo_element_helper==============================
18952  /// \short Helper function to create (halo) elements on the loop
18953  /// process based on the info received in send_and_received_located_info
18954  /// This function is in charge of verify if the element is associated to
18955  /// a boundary
18956  //======================================================================
18957  template<class ELEMENT>
18959  add_halo_element_helper(unsigned& iproc, FiniteElement* ele_pt)
18960  {
18961 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18962  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
18963  << " Bool: Element is associated to an original boundary "
18964  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18965  << std::endl;
18966 #endif
18967 
18968  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
18969  {
18970 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18971  oomph_info
18972  << "Rec:" << Counter_for_flat_packed_unsigneds
18973  << " How many boundaries are associated with the element "
18974  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18975  << std::endl;
18976 #endif
18977  const unsigned nassociated_boundaries =
18978  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18979 
18980  for (unsigned b = 0; b < nassociated_boundaries; b++)
18981  {
18982 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18983  oomph_info
18984  << "Rec:" << Counter_for_flat_packed_unsigneds
18985  << " Boundary associated to the element "
18986  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18987  << std::endl;
18988 #endif
18989  const unsigned bnd =
18990  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18991 
18992 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18993  oomph_info
18994  << "Rec:" << Counter_for_flat_packed_unsigneds
18995  << " Face index of the element "
18996  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18997  << std::endl;
18998 #endif
18999  const unsigned face_index =
19000  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19001 
19002  // Associate the element with the boundary and establish as many
19003  // face indexes it has
19004  this->Boundary_element_pt[bnd].push_back(ele_pt);
19005  this->Face_index_at_boundary[bnd].push_back(face_index);
19006 
19007  } // (b < nassociated_boundaries)
19008 
19009  // Here read the info. regarding the boundary-region of the element
19010 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19011  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19012  << " Bool: Element is associated to a boundary-region "
19013  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19014  << std::endl;
19015 #endif
19016 
19017  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
19018  {
19019 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19020  oomph_info
19021  << "Rec:" << Counter_for_flat_packed_unsigneds
19022  << " How many boundaries-regions are associated with the element "
19023  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19024  << std::endl;
19025 #endif
19026  const unsigned nassociated_boundaries_and_regions =
19027  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19028 
19029  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19030  {
19031 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19032  oomph_info
19033  << "Rec:" << Counter_for_flat_packed_unsigneds
19034  << " Boundary associated to the element "
19035  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19036  << std::endl;
19037 #endif
19038  const unsigned bnd =
19039  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19040 
19041 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19042  oomph_info
19043  << "Rec:" << Counter_for_flat_packed_unsigneds
19044  << " Region associated to the element "
19045  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19046  << std::endl;
19047 #endif
19048  const unsigned region =
19049  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19050 
19051 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19052  oomph_info
19053  << "Rec:" << Counter_for_flat_packed_unsigneds
19054  << " Face index of the element in boundary-region "
19055  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19056  << std::endl;
19057 #endif
19058  const unsigned face_index =
19059  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19060 
19061  // Associate the element with the boundary-regions and establish
19062  // as many face indexes it has
19063  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19064  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
19065 
19066  } // for (br < nassociated_boundaries_and_regions)
19067 
19068  } // Is the element associated with a boundary-region?
19069 
19070  }
19071 
19072  // Now check if the element is associated to a shared boundary
19073 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19074  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19075  << " Bool: Element is associated to a shared boundary "
19076  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19077  << std::endl;
19078 #endif
19079  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==3)
19080  {
19081 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19082  oomph_info
19083  << "Rec:" << Counter_for_flat_packed_unsigneds
19084  << " How many shared boundaries are associated with the element "
19085  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19086  << std::endl;
19087 #endif
19088  const unsigned nassociated_shared_boundaries =
19089  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19090 
19091  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19092  {
19093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19094  oomph_info
19095  << "Rec:" << Counter_for_flat_packed_unsigneds
19096  << " Shared boundary associated to the element "
19097  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19098  << std::endl;
19099 #endif
19100  const unsigned bnd =
19101  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19102 
19103 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19104  oomph_info
19105  << "Rec:" << Counter_for_flat_packed_unsigneds
19106  << " Face index of the element associated to the shared boundary "
19107  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19108  << std::endl;
19109 #endif
19110 
19111  const unsigned face_index =
19112  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19113 
19114  this->add_shared_boundary_element(bnd, ele_pt);
19115  this->add_face_index_at_shared_boundary(bnd, face_index);
19116 
19117  } // (b < nassociated_shared_boundaries)
19118 
19119  } // The element is associted with a shared boundary
19120 
19121  }
19122 
19123  //========start of add_halo_node_helper==========================
19124  /// Helper function to add halo node
19125  //===============================================================
19126  template<class ELEMENT>
19128  (Node* &new_nod_pt,
19129  Vector<Node*> &new_nodes_on_domain,
19130  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19131  &other_proc_shd_bnd_node_pt,
19132  unsigned& iproc,
19133  unsigned& node_index,
19134  FiniteElement* const &new_el_pt,
19135  Vector<Vector<Vector<unsigned> > > &global_node_names,
19136  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19137  Vector<Node*> &global_shared_node_pt)
19138  {
19139  // Given the node, received information about them from process
19140  // iproc, construct them on the current process
19141 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19142  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19143  << " Bool: New node needs to be constructed "
19144  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19145  << std::endl;
19146 #endif
19147  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
19148  {
19149  // Construct a new node based upon sent information, or copy a node
19150  // from one of the shared boundaries
19151  construct_new_halo_node_helper(new_nod_pt, new_nodes_on_domain,
19152  other_proc_shd_bnd_node_pt,
19153  iproc, node_index, new_el_pt,
19154  global_node_names,
19155  node_name_to_global_index,
19156  global_shared_node_pt);
19157  }
19158  else
19159  {
19160 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19161  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19162  << " Index of existing halo node "
19163  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19164  << std::endl;
19165 #endif
19166 
19167  // Copy node from received location
19168  new_nod_pt = new_nodes_on_domain[
19169  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
19170 
19171  new_el_pt->node_pt(node_index)=new_nod_pt;
19172 
19173  }
19174 
19175  }
19176 
19177  //========start of construct_new_halo_node_helper=================
19178  //Helper function which constructs a new external halo node (on new element)
19179  //with the required information sent from the haloed process
19180  //========================================================================
19181  template<class ELEMENT>
19183  (Node* &new_nod_pt,
19184  Vector<Node*> &new_nodes_on_domain,
19185  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19186  &other_proc_shd_bnd_node_pt,
19187  unsigned& iproc, unsigned& node_index,
19188  FiniteElement* const &new_el_pt,
19189  Vector<Vector<Vector<unsigned> > > &global_node_names,
19190  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19191  Vector<Node*> &global_shared_node_pt)
19192  {
19193  //The first entry indicates the number of values at this new Node
19194  //(which may be different across the same element e.g. Lagrange multipliers)
19195 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19196  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19197  << " Number of values of external halo node "
19198  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19199  << std::endl;
19200 #endif
19201  unsigned n_val=Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19202 
19203  // Null TimeStepper for now
19204  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
19205  // Default number of previous values to 1
19206  unsigned n_prev=time_stepper_pt->ntstorage();
19207 
19208  // ------------------------------------------------------
19209  // Check if the node is on an original boundary
19210 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19211  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19212  << " Is the node on an original boundary "
19213  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19214  << std::endl;
19215 #endif
19216 
19217  // Flag to indicate if the node is on original boundaries
19218  const unsigned node_on_original_boundaries =
19219  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19220 
19221  // Store the original boundaries where the node is on
19222  Vector<unsigned> original_boundaries_node_is_on;
19223  // Store the zeta coordinates of the node on the original boundaries
19224  Vector<double> zeta_coordinates;
19225  // Store the number of original boundaries the node is on
19226  unsigned n_original_boundaries_node_is_on = 0;
19227 
19228  if (node_on_original_boundaries==2)
19229  {
19230  // How many original boundaries does the node live on?
19231 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19232  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19233  << " Number of boundaries the node is on: "
19234  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19235  << std::endl;
19236 #endif
19237  n_original_boundaries_node_is_on =
19238  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19239 
19240  // Resize the containers
19241  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19242  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19243 
19244  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
19245  {
19246  // Boundary number
19247 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19248  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19249  << " Node is on boundary "
19250  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19251  << std::endl;
19252 #endif
19253  original_boundaries_node_is_on[i] =
19254  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19255  zeta_coordinates[i] =
19256  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19257  }
19258 
19259  } // if (node_on_original_boundaries==2)
19260 #ifdef PARANOID
19261  else
19262  {
19263  if (node_on_original_boundaries != 0)
19264  {
19265  std::ostringstream error_message;
19266  error_message
19267  <<"The current node is not on an original boundary, this should\n"
19268  <<"be indicated by a zero flag. However, the read value for\n"
19269  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
19270  throw OomphLibError(
19271  error_message.str(),
19272  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19273  OOMPH_EXCEPTION_LOCATION);
19274  } // if (node_on_original_boundaries != 0)
19275  }
19276 #endif
19277 
19278  // --------------------------------------------------------------
19279  // Check if the node was on a shared boundary with the iproc
19280  // processor
19281 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19282  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19283  << " Is node on shared boundary? "
19284  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19285  << std::endl;
19286 #endif
19287  const unsigned is_node_on_shared_boundary =
19288  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19289  if (is_node_on_shared_boundary == 1)
19290  {
19291  // How many shared boundaries does the node live on?
19292 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19293  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19294  << " Number of boundaries the node is on: "
19295  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19296  << std::endl;
19297 #endif
19298  const unsigned n_shd_bnd_node_is_on =
19299  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19300  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19301  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
19302  {
19303  // Shared boundary number
19304 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19305  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19306  << " Node is on boundary "
19307  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19308  << std::endl;
19309 #endif
19310  shd_bnds_node_is_on[i] =
19311  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19312  }
19313 
19314  // Get the index of the node on the shared boundary
19315 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19316  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19317  << " Index of node on boundary "
19318  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19319  << std::endl;
19320 #endif
19321  // Get the node index of the node on the shared boundary
19322  unsigned node_index_on_shared_boundary =
19323  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19324 
19325  // Get the pointer to the node with the received info.
19326  new_nod_pt =
19327  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
19328  node_index_on_shared_boundary);
19329 
19330  } // if (is_node_on_shared_boundary == 1)
19331 #ifdef PARANOID
19332  else
19333  {
19334  if (is_node_on_shared_boundary != 0)
19335  {
19336  std::ostringstream error_message;
19337  error_message
19338  <<"The current node is not on a shared boundary, this should\n"
19339  <<"be indicated by a zero flag. However, the read value for\n"
19340  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
19341  throw OomphLibError(
19342  error_message.str(),
19343  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19344  OOMPH_EXCEPTION_LOCATION);
19345  } // if (node_on_shared_boundary != 0)
19346  }
19347 #endif
19348 
19349  // ------------------------------------------------------------
19350  // Is the node on a shared boundary with other processor?
19351 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19352  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19353  << " Is the node on shared boundaries with other processors "
19354  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19355  << std::endl;
19356 #endif
19357 
19358  // Is the node in shared boundaries no associated with the
19359  // receiver processor
19360  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19361  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19362 
19363  // The containers where to store the info.
19364  Vector<unsigned> other_processor_1;
19365  Vector<unsigned> other_processor_2;
19366  Vector<unsigned> other_shared_boundaries;
19367  Vector<unsigned> other_indexes;
19368 
19369  // How many shared bounaries with other processors the node lives on
19370  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19371 
19372  // Is the node on shared boundaries with other processors
19373  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19374  {
19375 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19376  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19377  << " In how many shared boundaries with other "
19378  << "processors is the node "
19379  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19380  << std::endl;
19381 #endif
19382 
19383  // How many nodes on other shared boundaries were found
19384  n_shd_bnd_with_other_procs_have_node =
19385  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19386 
19387  // Resize the containers
19388  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19389  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19390  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19391  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19392 
19393  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19394  {
19395 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19396  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19397  << " Processor where the other shared boundary"
19398  << "has the node"
19399  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19400  << std::endl;
19401 #endif
19402  // Read the other processor 1
19403  other_processor_1[i] =
19404  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19405 
19406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19407  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19408  << " Processor where the other shared boundary"
19409  << "has the node"
19410  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19411  << std::endl;
19412 #endif
19413  // Read the other processor 2
19414  other_processor_2[i] =
19415  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19416 
19417 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19418  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19419  << " Other shared boundary id where the node is on: "
19420  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19421  << std::endl;
19422 #endif
19423 
19424  // Read the other shared boundary id
19425  other_shared_boundaries[i] =
19426  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19427 
19428 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19429  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19430  << " Node index on the other shared boundary "
19431  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19432  << std::endl;
19433 #endif
19434 
19435  // Read the node index on the other shared boundary
19436  other_indexes[i] =
19437  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19438 
19439  } // for (i < n_shd_bnd_with_other_procs_have_node)
19440 
19441  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19442 #ifdef PARANOID
19443  else
19444  {
19445  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19446  {
19447  std::ostringstream error_message;
19448  error_message
19449  <<"The current node is not on a shared boundary with\n"
19450  <<"other processors, this should be indicated by a zero flag.\n"
19451  <<"However, the read value for that flag is ("
19452  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
19453  throw OomphLibError(
19454  error_message.str(),
19455  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19456  OOMPH_EXCEPTION_LOCATION);
19457  }
19458  }
19459 #endif
19460 
19461  // Now we have all the info. to decide whether the node should be
19462  // created or not
19463 
19464  // First check if the node is a shared boundary node
19465  if (is_node_on_shared_boundary == 1)
19466  {
19467  // We already have the node, we do not need to create it
19468 
19469  // Only check if we need to add boundary info. to the node
19470  if (node_on_original_boundaries==2)
19471  {
19472  // The node is a boundary node, add the boundary info. before
19473  // adding it to the domain
19474 
19475  // Associate the node to the given boundaries
19476  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19477  {
19478  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19479  // Establish the boundary coordinates for the node
19480  Vector<double> zeta(1);
19481  zeta[0] = zeta_coordinates[i];
19482  new_nod_pt->set_coordinates_on_boundary(
19483  original_boundaries_node_is_on[i],zeta);
19484  }
19485 
19486  } // if (node_on_original_boundaries==2)
19487 
19488  // Add the node to the domain
19489  new_nodes_on_domain.push_back(new_nod_pt);
19490 
19491  // Add the node to the element
19492  new_el_pt->node_pt(node_index) = new_nod_pt;
19493 
19494  } // if (is_node_on_shared_boundary == 1)
19495 
19496  // Now check if the node is on a shared boundary with another
19497  // processor, if that is the case try to find the node that may have
19498  // been already sent by the other processors
19499 
19500  // This flags indicates if the node was found, and then decide if it
19501  // is required to create the node
19502  bool found_node_in_other_shared_boundaries = false;
19503  // Flag to indicate whether the node should be created as a boundary
19504  // node or not. If the node lies on a shared boundary with other
19505  // processor the we create it as a boundary node. The processor from
19506  // which we are receiving info. (iproc) may not know that the node
19507  // lies on an original boundary. If the node lies on an original
19508  // boundary then its info. will be sent by another processor, then
19509  // we can set its boundary info. since the node was constructed as a
19510  // boundary node
19511  bool build_node_as_boundary_node = false;
19512 
19513  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19514  {
19515  // Build the node as a boundary node
19516  build_node_as_boundary_node = true;
19517 
19518  // Try to get the node pointer in case that the node has been
19519  // already sent by the other processors
19520 
19521  // Get the number of initial shared boundaries to correct the
19522  // index of the shared boundary
19523  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19524 
19525  // Add the found nodes in the container
19526  Vector<Node*> found_node_pt;
19527 
19528  // Now try to find the node in any of the other shared boundaries
19529  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19530  {
19531  // We always check with the lower processor number. The
19532  // info. is only stored in one direction. More importantly,
19533  // this is done with the hope that the info. has been already
19534  // received from the other processor given that its info. was
19535  // processed before the current processor (iproc). NOTE that
19536  // it is not always the case that this info. has been received
19537  // from the other processors since it may have not require to
19538  // send the elements (and nodes) on the shared boundary with
19539  // the current processor (iproc).
19540  unsigned oproc1 = other_processor_1[i];
19541  unsigned oproc2 = other_processor_2[i];
19542  if (other_processor_1[i] > other_processor_2[i])
19543  {
19544  oproc1 = other_processor_2[i];
19545  oproc2 = other_processor_1[i];
19546  } // if (other_processor_1[i] > other_processor_2[i])
19547 
19548  // Re-compute the shared boundary id between the other
19549  // processors
19550  const unsigned shd_bnd_id =
19551  other_shared_boundaries[i] - initial_shd_bnd_id;
19552 
19553  // Read the index
19554  const unsigned index = other_indexes[i];
19555 
19556  // Check if there are nodes received from the other processor
19557  // and with the given shared boundary
19558  const unsigned n_nodes_on_other_processor =
19559  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19560 
19561  if (n_nodes_on_other_processor > 0)
19562  {
19563  // Check if we can find the index of the node in that
19564  // other processor and shared boundary id
19565  std::map<unsigned, Node*>::iterator it =
19566  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
19567  find(index);
19568 
19569  // If the index exist then get the node pointer
19570  if (it!=
19571  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19572  {
19573  // Mark the node as found
19574  found_node_in_other_shared_boundaries = true;
19575  // Get the node pointer
19576  Node* tmp_node_pt = (*it).second;
19577 
19578  // Push back the node pointer
19579  found_node_pt.push_back(tmp_node_pt);
19580 
19581  } // if (it!=
19582  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19583 
19584  } // if (n_nodes_on_other_processor > 0)
19585 
19586  } // for (i < n_shd_bnd_with_other_procs_have_node)
19587 
19588  // If the node was found, then all their instances should be the
19589  // same but better check
19590  if (found_node_in_other_shared_boundaries)
19591  {
19592 #ifdef PARANOID
19593  const unsigned n_times_node_found = found_node_pt.size();
19594  for (unsigned j = 1; j < n_times_node_found; j++)
19595  {
19596  if (found_node_pt[j-1] != found_node_pt[j])
19597  {
19598  std::ostringstream error_message;
19599  error_message
19600  <<"The instances of the node that was found on\n"
19601  <<"shared boundaries with other processors (but not\n"
19602  <<"on shared boundaries with this processor) are not\n"
19603  <<"the same.\n"
19604  <<"These are the coordinates of the instances of the\n"
19605  <<"nodes:\n"
19606  <<"(" << found_node_pt[j-1]->x(0) << ", "
19607  << found_node_pt[j-1]->x(1) << ")\n"
19608  <<"(" << found_node_pt[j]->x(0) << ", "
19609  << found_node_pt[j]->x(1) << ")\n"
19610  <<"Dont be surprised if they are the same since the "
19611  << "node is\nrepeated.\n";
19612  throw OomphLibError(error_message.str(),
19613  OOMPH_CURRENT_FUNCTION,
19614  OOMPH_EXCEPTION_LOCATION);
19615 
19616  } // if (found_node_pt[j-1] != found_node_pt[j])
19617 
19618  } // for (j < ntimes_node_found)
19619 #endif // #ifdef PARANOID
19620 
19621  // Check if the node is a shared boundary node from the
19622  // current processor and the iproc processor, if that is the
19623  // case, and the node is also on a shared boundary with other
19624  // processor, then the pointer should be the same!!!
19625  if (is_node_on_shared_boundary == 1)
19626  {
19627  //const unsigned n_times_node_found = found_node_pt.size();
19628  // The pointer to the node is already assigned, it was
19629  // assigned when the node was found to be on a shared
19630  // boundary with the sending processor (iproc). Check that
19631  // any previous instances of the node have been copied
19632  // from the shared boundary, if that is not the case then
19633  // there is a problem
19634  if (found_node_pt[0] != new_nod_pt)
19635  {
19636  std::ostringstream error_message;
19637  error_message
19638  <<"The pointer of the node that was found to be on a\n"
19639  <<"shared boundary with other processor(s) and the pointer\n"
19640  <<"of the node on shared boundary with the receiver\n"
19641  <<"processor (iproc) are not the same. This means we have a\n"
19642  << "repeated node)\n"
19643  <<"The coordinates for the nodes are:\n"
19644  <<"(" << found_node_pt[0]->x(0) << ", "
19645  << found_node_pt[0]->x(1) << ")\n"
19646  <<"(" << new_nod_pt->x(0) << ", "
19647  << new_nod_pt->x(1) << ")\n"
19648  <<"Dont be surprised if they are the same since the "
19649  << "node is\nrepeated.\n";
19650  throw OomphLibError(error_message.str(),
19651  OOMPH_CURRENT_FUNCTION,
19652  OOMPH_EXCEPTION_LOCATION);
19653 
19654  } // if (found_node_pt[i] != new_nod_pt)
19655 
19656  } // if (is_node_on_shared_boundary == 1)
19657  else
19658  {
19659  // Take the first instance of the node in case that it was
19660  // found and is not on a shared boundary with the iproc
19661  // processor (the processor from which we are receiving
19662  // the info.)
19663  new_nod_pt = found_node_pt[0];
19664 
19665  }
19666 
19667  } // if (found_node_in_other_shared_boundaries)
19668 
19669  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19670 
19671  // -----------------------------------------------------------------
19672  // Create the node or read the received info if the node is not on a
19673  // shared boundary with the iproc processor
19674  if (is_node_on_shared_boundary != 1)
19675  {
19676  // If the node is on a shared boundary with other processor we
19677  // need to read all the info. since the processor that sent the
19678  // info. did not know that the node is part of another shared
19679  // boundary
19680 
19681  // If the node is not on a shared boundary (with any processor),
19682  // or if this is the first time that the info. of the node is
19683  // received from any of the processors with which it has a shared
19684  // boundary, then we create the node
19685 
19686  // Is the node a boundary node or should it be build as a boundary
19687  // node because it is on a shared boundary with other processors
19688  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
19689  {
19690  // Check if necessary to create the node, or if it has been
19691  // already found in shared boundaries with other processors
19692  if (!found_node_in_other_shared_boundaries)
19693  {
19694  // Construct a boundary node
19695  if (time_stepper_pt!=0)
19696  {
19697  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
19698  time_stepper_pt);
19699  }
19700  else
19701  {
19702  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
19703  }
19704 
19705  } // if (!found_node_in_other_shared_boundaries)
19706  else
19707  {
19708  // If the node was found then assign the node to the element
19709  new_el_pt->node_pt(node_index) = new_nod_pt;
19710 
19711  } // else if (!found_node_in_other_shared_boundaries)
19712 
19713  // Associate the node to the given boundaries
19714  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19715  {
19716  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19717  // Establish the boundary coordinates for the node
19718  Vector<double> zeta(1);
19719  zeta[0] = zeta_coordinates[i];
19720  new_nod_pt->set_coordinates_on_boundary(
19721  original_boundaries_node_is_on[i],zeta);
19722  }
19723 
19724  } // if (node is on an original boundary)
19725  else
19726  {
19727  // Check if necessary to create the node, or if it has been
19728  // already found in shared boundaries with other processors
19729  if (!found_node_in_other_shared_boundaries)
19730  {
19731  // Construct an ordinary (non-boundary) node
19732  if (time_stepper_pt!=0)
19733  {
19734  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
19735  }
19736  else
19737  {
19738  new_nod_pt=new_el_pt->construct_node(node_index);
19739  }
19740  } // if (!found_node_in_other_shared_boundaries)
19741  else
19742  {
19743  // If the node was found then assign the node to the element
19744  new_el_pt->node_pt(node_index) = new_nod_pt;
19745  } // else if (!found_node_in_other_shared_boundaries)
19746 
19747  } // else (the node is not a boundary node)
19748 
19749  // ... and gather all its information
19750 
19751  // If the node was found or not in other shared boundaries, this
19752  // is the first time the node is received from this processor
19753  // (iproc), therefore it is added to the vector of nodes received
19754  // from this processor (iproc)
19755  new_nodes_on_domain.push_back(new_nod_pt);
19756 
19757  // Check if necessary to state all the info. to the node if it has
19758  // been already found in shared boundaries with other processors
19759  if (!found_node_in_other_shared_boundaries)
19760  {
19761  // Add the node to the general node storage
19762  this->add_node_pt(new_nod_pt);
19763  } // if (!found_node_in_other_shared_boundaries)
19764 
19765  // Is the new constructed node Algebraic?
19766  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
19767  (new_nod_pt);
19768 
19769  // If it is algebraic, its node update functions will
19770  // not yet have been set up properly
19771  if (new_alg_nod_pt!=0)
19772  {
19773  // The AlgebraicMesh is the external mesh
19774  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
19775 
19776  /// The first entry of All_alg_nodal_info contains
19777  /// the default node update id
19778  /// e.g. for the quarter circle there are
19779  /// "Upper_left_box", "Lower right box" etc...
19780 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19781  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19782  << " Alg node update id "
19783  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19784  << std::endl;
19785 #endif
19786 
19787  unsigned update_id=Flat_packed_unsigneds
19788  [Counter_for_flat_packed_unsigneds++];
19789 
19790  Vector<double> ref_value;
19791 
19792  // The size of this vector is in the next entry
19793  // of All_alg_nodal_info
19794 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19795  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19796  << " Alg node # of ref values "
19797  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19798  << std::endl;
19799 #endif
19800  unsigned n_ref_val=Flat_packed_unsigneds
19801  [Counter_for_flat_packed_unsigneds++];
19802 
19803  // The reference values themselves are in
19804  // All_alg_ref_value
19805  ref_value.resize(n_ref_val);
19806  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
19807  {
19808  ref_value[i_ref]=Flat_packed_doubles
19809  [Counter_for_flat_packed_doubles++];
19810  }
19811 
19812  Vector<GeomObject*> geom_object_pt;
19813  /// again we need the size of this vector as it varies
19814  /// between meshes; we also need some indication
19815  /// as to which geometric object should be used...
19816 
19817  // The size of this vector is in the next entry
19818  // of All_alg_nodal_info
19819 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19820  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19821  << " Alg node # of geom objects "
19822  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19823  << std::endl;
19824 #endif
19825  unsigned n_geom_obj=Flat_packed_unsigneds
19826  [Counter_for_flat_packed_unsigneds++];
19827 
19828  // The remaining indices are in the rest of
19829  // All_alg_nodal_info
19830  geom_object_pt.resize(n_geom_obj);
19831  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
19832  {
19833 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19834  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19835  << " Alg node: geom object index "
19836  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19837  << std::endl;
19838 #endif
19839  unsigned geom_index=Flat_packed_unsigneds
19840  [Counter_for_flat_packed_unsigneds++];
19841  // This index indicates which of the AlgebraicMesh's
19842  // stored geometric objects should be used
19843  // (0 is a null pointer; everything else should have
19844  // been filled in by the specific Mesh). If it
19845  // hasn't been filled in then the update_node_update
19846  // call should fix it
19847  geom_object_pt[i_geom]=alg_mesh_pt->
19848  geom_object_list_pt(geom_index);
19849  }
19850 
19851  // Check if necessary to state all the info. to the node if it has
19852  // been already found in shared boundaries with other processors
19853  if (!found_node_in_other_shared_boundaries)
19854  {
19855  /// For the received update_id, ref_value, geom_object
19856  /// call add_node_update_info
19857  new_alg_nod_pt->add_node_update_info
19858  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
19859 
19860  /// Now call update_node_update
19861  alg_mesh_pt->update_node_update(new_alg_nod_pt);
19862 
19863  } // if (!found_node_in_other_shared_boundaries)
19864 
19865  } // if (new_alg_nod_pt!=0)
19866 
19867  // Check if necessary to state all the info. to the node if it has
19868  // been already found in shared boundaries with other processors
19869  if (!found_node_in_other_shared_boundaries)
19870  {
19871  // Is the node a MacroElementNodeUpdateNode?
19872  MacroElementNodeUpdateNode* macro_nod_pt=
19873  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
19874 
19875  if (macro_nod_pt!=0)
19876  {
19877  // Need to call set_node_update_info; this requires
19878  // a Vector<GeomObject*> (taken from the mesh)
19879  Vector<GeomObject*> geom_object_vector_pt;
19880 
19881  // Access the required geom objects from the
19882  // MacroElementNodeUpdateMesh
19883  MacroElementNodeUpdateMesh* macro_mesh_pt=
19884  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
19885  geom_object_vector_pt=
19886  macro_mesh_pt->geom_object_vector_pt();
19887 
19888  // Get local coordinate of node in new element
19889  Vector<double> s_in_macro_node_update_element;
19890  new_el_pt->local_coordinate_of_node
19891  (node_index,s_in_macro_node_update_element);
19892 
19893  // Set node update info for this node
19894  macro_nod_pt->set_node_update_info
19895  (new_el_pt,s_in_macro_node_update_element,
19896  geom_object_vector_pt);
19897  }
19898 
19899  } // if (!found_node_in_other_shared_boundaries)
19900 
19901  // If there are additional values, resize the node
19902  unsigned n_new_val=new_nod_pt->nvalue();
19903 
19904  // Check if necessary to state all the info. to the node if it has
19905  // been already found in shared boundaries with other processors
19906  if (!found_node_in_other_shared_boundaries)
19907  {
19908  if (n_val>n_new_val)
19909  {
19910  // If it has been necessary to resize then it may be becuse
19911  // the node is on a FSI boundary, if that is the case we need
19912  // to set a map for these external values
19913 
19914  // Cast to a boundary node
19915  BoundaryNodeBase *bnod_pt =
19916  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
19917 
19918  // Create storage, if it doesn't already exist, for the map
19919  // that will contain the position of the first entry of
19920  // this face element's additional values,
19921  if(bnod_pt->index_of_first_value_assigned_by_face_element_pt()==0)
19922  {
19923  bnod_pt->index_of_first_value_assigned_by_face_element_pt()=
19924  new std::map<unsigned, unsigned>;
19925  }
19926 
19927  // Get pointer to the map
19928  std::map<unsigned, unsigned>* map_pt=
19929  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
19930 
19931  // The id of the face to which this node belong in the bulk
19932  // element
19933  const unsigned id_face = 0;
19934  // We only resize the node values Vector if we haven't done it yet
19935  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
19936 
19937  // If this node hasn't been resized for current id
19938  if(p==map_pt->end())
19939  {
19940  // assign the face element id and the position of the
19941  //first entry to the boundary node
19942  (*map_pt)[id_face] = n_new_val;
19943 
19944  // resize the node vector of values
19945  new_nod_pt->resize(n_val);
19946  }
19947 
19948  } // if (n_val>n_new_val)
19949 
19950  } // if (!found_node_in_other_shared_boundaries)
19951 
19952  // Is the new node a SolidNode?
19953  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
19954  if (solid_nod_pt!=0)
19955  {
19956  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
19957  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
19958  {
19959  for (unsigned t=0;t<n_prev;t++)
19960  {
19961  double read_data =
19962  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19963 
19964  // Check if necessary to state all the info. to the node if it has
19965  // been already found in shared boundaries with other processors
19966  if (!found_node_in_other_shared_boundaries)
19967  {
19968  solid_nod_pt->variable_position_pt()->
19969  set_value(t, i_val, read_data);
19970  } // if (!found_node_in_other_shared_boundaries)
19971 
19972  }
19973 
19974  }
19975 
19976 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19977  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19978  << " Number of values solid node: "
19979  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19980  << std::endl;
19981 #endif
19982  const unsigned nvalues_solid_node =
19983  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19984  Vector<double> values_solid_node(nvalues_solid_node);
19985  for (unsigned i = 0; i < nvalues_solid_node; i++)
19986  {
19987  values_solid_node[i] =
19988  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19989  }
19990 
19991  // Check if necessary to state all the info. to the node if it has
19992  // been already found in shared boundaries with other processors
19993  if (!found_node_in_other_shared_boundaries)
19994  {
19995  unsigned index = 0;
19996  solid_nod_pt->read_values_from_vector(values_solid_node, index);
19997  }
19998 
19999  }
20000 
20001  // Get copied history values
20002  // unsigned n_val=new_nod_pt->nvalue();
20003  for (unsigned i_val=0;i_val<n_val;i_val++)
20004  {
20005  for (unsigned t=0;t<n_prev;t++)
20006  {
20007  double read_data =
20008  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20009 
20010  // Check if necessary to state all the info. to the node if it
20011  // has been already found in shared boundaries with other
20012  // processors
20013  if (!found_node_in_other_shared_boundaries)
20014  {
20015  new_nod_pt->set_value(t, i_val, read_data);
20016  } // if (!found_node_in_other_shared_boundaries)
20017 
20018  }
20019 
20020  }
20021 
20022  // Get copied history values for positions
20023  unsigned n_dim=new_nod_pt->ndim();
20024  for (unsigned idim=0;idim<n_dim;idim++)
20025  {
20026  for (unsigned t=0;t<n_prev;t++)
20027  {
20028  double read_data =
20029  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20030 
20031  // Check if necessary to state all the info. to the node if it
20032  // has been already found in shared boundaries with other
20033  // processors
20034  if (!found_node_in_other_shared_boundaries)
20035  {
20036  // Copy to coordinate
20037  new_nod_pt->x(t,idim) = read_data;
20038 
20039  } // if (!found_node_in_other_shared_boundaries)
20040  }
20041  }
20042 
20043  } // if (is_node_on_shared_boundary != 1)
20044 
20045  // If the node was not found in other shared boundaries (possibly
20046  // because it is the first time the node has been sent) then copy
20047  // the node to the shared boundaries where it should be, use the
20048  // special container for this cases
20049  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20050  // shared
20051  // boundaries with
20052  // other processors
20053  !found_node_in_other_shared_boundaries) // The node has not
20054  // been previously
20055  // set as
20056  // shared with
20057  // other processors
20058  // (first time)
20059  {
20060  // Update the node pointer in all the (references) of the node
20061  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20062  other_proc_shd_bnd_node_pt,
20063  other_processor_1,
20064  other_processor_2,
20065  other_shared_boundaries,
20066  other_indexes,
20067  global_node_names,
20068  node_name_to_global_index,
20069  global_shared_node_pt);
20070 
20071  } // if (!found_node_in_other_shared_boundaries)
20072 
20073  }
20074 
20075 //========start of update_other_proc_shd_bnd_node_helper=================
20076 //Helper function that assigns/updates the references to the node so
20077 //that it can be found with any other reference
20078 //========================================================================
20079 template<class ELEMENT>
20082 (Node* &new_node_pt,
20083  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
20084  &other_proc_shd_bnd_node_pt,
20085  Vector<unsigned> &other_processor_1,
20086  Vector<unsigned> &other_processor_2,
20087  Vector<unsigned> &other_shared_boundaries,
20088  Vector<unsigned> &other_indexes,
20089  Vector<Vector<Vector<unsigned> > > &global_node_names,
20090  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
20091  Vector<Node*> &global_shared_node_pt)
20092 {
20093  // Get the number of initial shared boundaries to correct the index
20094  // of the shared boundary
20095  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20096 
20097 #ifdef PARANOID
20098  // Get the number of instances of the node on other shared
20099  // boundaries with other processors
20100  const unsigned n_data = other_processor_1.size();
20101 #endif // #ifdef PARANOID
20102 
20103  // Create the first node name
20104  Vector<unsigned> node_name(4);
20105  node_name[0] = other_processor_1[0];
20106  node_name[1] = other_processor_2[0];
20107  node_name[2] = other_shared_boundaries[0];
20108  node_name[3] = other_indexes[0];
20109 
20110 #ifdef PARANOID
20111  // Get the global node index, and all the names of the node
20112  std::map<Vector<unsigned>, unsigned>::iterator it =
20113  node_name_to_global_index.find(node_name);
20114  if (it==node_name_to_global_index.end())
20115  {
20116  std::ostringstream error_stream;
20117  error_stream
20118  <<"The node name does not exist in the global node names\n"
20119  <<"This is the name of the node\n"
20120  << "Name: iproc, jproc, ishd_bnd, idx\n"
20121  <<"Name: " << node_name[0] <<", " << node_name[1] <<", "
20122  << node_name[2] <<", " << node_name[3] <<"\n";
20123  throw OomphLibError(error_stream.str(),
20124  OOMPH_CURRENT_FUNCTION,
20125  OOMPH_EXCEPTION_LOCATION);
20126  } // if (it!=node_name_to_global_index.end())
20127 #endif // #ifdef PARANOID
20128 
20129  // Get the global node index
20130  const unsigned iglobal_node = node_name_to_global_index[node_name];
20131  // Add the node to the global shared node container
20132  global_shared_node_pt[iglobal_node] = new_node_pt;
20133  // Get the names
20134  Vector<Vector<unsigned> > inode_names = global_node_names[iglobal_node];
20135  // Get the number of names of the node
20136  const unsigned n_names = inode_names.size();
20137 
20138 #ifdef PARANOID
20139  // Check that the received names of the node are part of the global
20140  // node names
20141  unsigned n_found_node_names_on_global_node_name = 0;
20142  // loop over the input node names
20143  for (unsigned j = 0; j < n_data; j++)
20144  {
20145  // loop over the inode_names
20146  for (unsigned k = 0; k < n_names; k++)
20147  {
20148  // Is this input name part of the global node names?
20149  if (inode_names[k][0] == other_processor_1[j] &&
20150  inode_names[k][1] == other_processor_2[j] &&
20151  inode_names[k][2] == other_shared_boundaries[j] &&
20152  inode_names[k][3] == other_indexes[j])
20153  {
20154  // Increase the number of found input node names in the
20155  // global node names
20156  n_found_node_names_on_global_node_name++;
20157  }
20158 
20159  } // for (k < n_names)
20160 
20161  } // for (j < n_data)
20162 
20163  // Were all the input node names found on the global node names?
20164  if (n_found_node_names_on_global_node_name != n_data)
20165  {
20166  std::ostringstream error_stream;
20167  error_stream
20168  <<"Not all the node names of the current node were found on the\n"
20169  <<"global node names. This happened when adding the node pointer\n"
20170  <<"to the data structure that keeps tracks of nodes on shared\n"
20171  <<"boundaries with other processors\n\n"
20172  << "These are the names of the current node\n"
20173  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20174  for (unsigned j = 0; j < n_data; j++)
20175  {
20176  error_stream<<"Name("<<j<<"): "
20177  <<other_processor_1[j] <<", "
20178  <<other_processor_2[j] <<", "
20179  <<other_shared_boundaries[j] <<", "
20180  <<other_indexes[j] <<"\n";
20181  }
20182 
20183  error_stream
20184  << "\n\nThese are the names of the global node\n"
20185  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20186  for (unsigned k = 0; k < n_names; k++)
20187  {
20188  error_stream<<"Name("<<k<<"): "
20189  <<inode_names[k][0] <<", "
20190  <<inode_names[k][1] <<", "
20191  <<inode_names[k][2] <<", "
20192  <<inode_names[k][3] <<"\n";
20193  }
20194 
20195  throw OomphLibError(error_stream.str(),
20196  OOMPH_CURRENT_FUNCTION,
20197  OOMPH_EXCEPTION_LOCATION);
20198  }
20199 #endif // #ifdef PARANOID
20200 
20201  // Set the node pointer in all of its names
20202  for (unsigned j = 0; j < n_names; j++)
20203  {
20204  // Get the j-th node name
20205  const unsigned iproc = inode_names[j][0];
20206  const unsigned jproc = inode_names[j][1];
20207  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20208  const unsigned index = inode_names[j][3];
20209 
20210  // The info. is stored only in one direction
20211  // Get the smallest processor number
20212  if (iproc < jproc)
20213  {
20214  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]
20215  = new_node_pt;
20216  }
20217  else
20218  {
20219  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]
20220  = new_node_pt;
20221  }
20222 
20223  } // for (j < n_names)
20224 
20225 }
20226 
20227  // *********************************************************************
20228  // End communication functions
20229  // *********************************************************************
20230 
20231  // *********************************************************************
20232  // BEGIN: Methods to perform load balance
20233  // *********************************************************************
20234 
20235  //======================================================================
20236  /// \short Performs the load balancing for unstructured meshes, the
20237  /// load balancing strategy is based on mesh migration
20238  //======================================================================
20239  template <class ELEMENT>
20241  load_balance(const Vector<unsigned>&
20242  target_domain_for_local_non_halo_element)
20243  {
20244  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20245 
20246  // This method can only be called when the mesh has been already
20247  // distributed
20248  if (!this->is_mesh_distributed())
20249  {
20250  std::ostringstream warning_message;
20251  warning_message
20252  << "\n===============================================================\n"
20253  << "The load balancing can only be performed in distributed meshes,\n"
20254  << "your mesh has not been distributed.\n"
20255  << "===============================================================\n\n";
20256  OomphLibWarning(warning_message.str(),
20257  OOMPH_CURRENT_FUNCTION,
20258  OOMPH_EXCEPTION_LOCATION);
20259  // Return
20260  return;
20261  }
20262 
20263  // Get the number of processors
20264  const unsigned nproc = this->communicator_pt()->nproc();
20265  // Get the rank of the current processors
20266  const unsigned my_rank = this->communicator_pt()->my_rank();
20267 
20268  // Check that there are at least two processors
20269  if (nproc == 1)
20270  {
20271  std::ostringstream warning_message;
20272  warning_message
20273  << "\n===============================================================\n"
20274  << "The load balancing can only be performed when there are at least\n"
20275  << "two procesors, the current number of processors is one.\n"
20276  << "===============================================================\n\n";
20277  OomphLibWarning(warning_message.str(),
20278  OOMPH_CURRENT_FUNCTION,
20279  OOMPH_EXCEPTION_LOCATION);
20280  // Return
20281  return;
20282  }
20283 
20284  // Get the time before load balance
20285  double t_start_overall_load_balance=0.0;
20286  if (Print_timings_level_load_balance>1)
20287  {
20288  t_start_overall_load_balance=TimingHelpers::timer();
20289  }
20290 
20291  // Get the number of elements in the mesh before load balance
20292  const unsigned nelement_before_load_balance = this->nelement();
20293 
20294 #ifdef PARANOID
20295  // The number of elements in the mesh and the number of target
20296  // domains for the local non halo elements in the mesh should match
20297  if (nnon_halo_element() !=
20298  target_domain_for_local_non_halo_element.size())
20299  {
20300  std::ostringstream error_message;
20301  error_message
20302  << "The number of non halo elements in the current mesh ("
20303  << nnon_halo_element() << ") and the number\n"
20304  << "of target areas for the local non halo elements ("
20305  << target_domain_for_local_non_halo_element.size()
20306  << ") is different\n\n";
20307  throw OomphLibError(error_message.str(),
20308  OOMPH_CURRENT_FUNCTION,
20309  OOMPH_EXCEPTION_LOCATION);
20310  }
20311 #endif
20312 
20313  // Backup pointers to elements in this mesh
20314  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20315  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20316  {
20317  backed_up_ele_pt[e] = this->finite_element_pt(e);
20318  }
20319 
20320  // =====================================================================
20321  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20322  // =====================================================================
20323 
20324  // Get the time to get the domains of halo elements
20325  double tt_start_get_domains_halo_elements=0.0;
20326  if (Print_timings_level_load_balance>1)
20327  {
20328  tt_start_get_domains_halo_elements=TimingHelpers::timer();
20329  }
20330 
20331  // Get the new domains for the halo elements
20332 
20333  // Send the new domains for the current haloed elements, and receive
20334  // the new domains for the current halo elements
20335  // -- 1) On the current processor get the new domains for the
20336  // haloed elements
20337  // -- 2) Then send this info. to all the processor that have a
20338  // halo copy of the element
20339 
20340  // The storing for the new domains of the haloed elements (sent to
20341  // other processors)
20342  Vector<Vector<unsigned> > new_domains_haloed_elements(nproc);
20343  // The storing for the new domains of the halo elements (received
20344  // from other processors)
20345  Vector<Vector<unsigned> > new_domains_halo_elements(nproc);
20346 
20347  // First resize the containers by getting the current number of
20348  // halo/haloed elements within each processor
20349  for (unsigned iproc = 0; iproc < nproc; iproc++)
20350  {
20351  // There are no halo/haloed elements with myself (my_rank
20352  // processor)
20353  if (iproc != my_rank)
20354  {
20355  // Get the number of halo elements with iproc processor
20356  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20357  // Resize the container
20358  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20359 
20360  // Get the number of haloed elements with iproc processor
20361  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20362  // Resize the container
20363  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20364  } // if (iproc != my_rank)
20365  } // for (iproc < nproc)
20366 
20367 #ifdef PARANOID
20368  // Count the number of found haloed elements
20369  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20370 #endif
20371 
20372  // Go through all the haloed elements and find their new domain
20373 
20374  // Get the haloed elements with in each processor and check if the
20375  // element is haloed with the processor
20376  for (unsigned iproc = 0; iproc < nproc; iproc++)
20377  {
20378  // There are no halo/haloed elements with myself (my_rank
20379  // processor)
20380  if (iproc != my_rank)
20381  {
20382  // Get the number of haloed elements with iproc processor
20383  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20384 
20385  // Loop over the haloed elements
20386  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20387  {
20388  // Get the ihd-th haloed element with "iproc" processor
20389  GeneralisedElement* haloed_ele_pt =
20390  this->root_haloed_element_pt(iproc, ihd);
20391 
20392  // The counter for the nonhalo elements
20393  unsigned nh_count4 = 0;
20394  // Find the element in the general elements container
20395  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20396  {
20397  // Get the e-th element
20398  GeneralisedElement* ele_pt = this->element_pt(e);
20399  // Check if the element is a nonhalo element
20400  if (!ele_pt->is_halo())
20401  {
20402  // Increase the counter for nonhalo elements, in case the
20403  // haloed element is found get the (nh_count4-1) position
20404  // in the target domains vector
20405  nh_count4++;
20406 
20407  if (ele_pt == haloed_ele_pt)
20408  {
20409  // Get the new domain for this element
20410  const unsigned element_domain =
20411  target_domain_for_local_non_halo_element[nh_count4-1];
20412  // Here decrease the counter ---------------------^
20413 
20414  // Set the new domain for the haloed element in the
20415  // special container
20416  new_domains_haloed_elements[iproc][ihd] = element_domain;
20417 #ifdef PARANOID
20418  // Increase the counter
20419  counter_for_found_haloed_elements[iproc]++;
20420 #endif
20421  // ... and break the "for" with the general
20422  // elements. Continue with the next haloed element
20423  break;
20424 
20425  } // if (ele_pt == haloed_ele_pt))
20426 
20427  } // if (!ele_pt->is_halo())
20428 
20429  } // for (e < nelement_before_load_balance)
20430 
20431  } // for (ihd < n_haloed_iproc)
20432 
20433  } // if (iproc != my_rank)
20434 
20435  } // for (iproc < nproc)
20436 
20437 #ifdef PARANOID
20438  // Check that all the haloed elements with all processors have been
20439  // found
20440  for (unsigned iproc = 0; iproc < nproc; iproc++)
20441  {
20442  // There are no halo/haloed elements with myself (my_rank
20443  // processor)
20444  if (iproc != my_rank)
20445  {
20446  // Get the number of haloed elements with "iproc" processor
20447  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20448 
20449  // Compare the number of found haloed elements with the current
20450  // number of haloed elements
20451  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20452  {
20453  std::ostringstream error_message;
20454  error_message
20455  << "The independent counting of found haloed elements ("
20456  << counter_for_found_haloed_elements[iproc] << ") with processor ("
20457  << iproc << ") is not equal to the number of haloed elements ("
20458  << n_haloed_iproc << ") with processor (" << iproc << ")\n";
20459  throw OomphLibError(error_message.str(),
20460  OOMPH_CURRENT_FUNCTION,
20461  OOMPH_EXCEPTION_LOCATION);
20462  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20463 
20464  } // if (iproc != my_rank)
20465 
20466  } // for (iproc < nproc)
20467 #endif
20468 
20469  // Now we have the new domains for the haloed elements
20470 
20471  // Send this info. to the processor with a halo copy of the haloed
20472  // elements and set the new domains in the halo copies
20473 
20474  // First put all the info. in a flat package array
20475  Vector<unsigned> new_domains_haloed_flat_unsigned;
20476  // Put in a vector the number of haloed elements within each
20477  // processor
20478  Vector<int> nhaloed_elements_with_iproc(nproc);
20479  for (unsigned iproc = 0; iproc < nproc; iproc++)
20480  {
20481  // There are no halo/haloed elements with myself (my_rank
20482  // processor)
20483  if (iproc != my_rank)
20484  {
20485  // Get the number of haloed elements with "iproc" processor
20486  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20487  // Copy the number of haloed elements with "iproc" processor
20488  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20489  // Copy the new domains of the haloed elements in the flat
20490  // package
20491  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20492  {
20493  new_domains_haloed_flat_unsigned.push_back(
20494  new_domains_haloed_elements[iproc][i]);
20495  } // for (i < n_haloed_ele_iproc)
20496 
20497  } // if (iproc != my_rank)
20498 
20499  } // for (iproc < nproc)
20500 
20501  // The offsets of the flat package within each processor
20502  Vector<int> offset_haloed_elements_with_iproc(nproc);
20503  offset_haloed_elements_with_iproc[0] = 0;
20504  for (unsigned ip = 1; ip < nproc; ip++)
20505  {
20506  // Compute the offset to send the values to each processor
20507  offset_haloed_elements_with_iproc[ip] =
20508  offset_haloed_elements_with_iproc[ip-1] +
20509  nhaloed_elements_with_iproc[ip-1];
20510  } // for (ip < nproc)
20511 
20512  // Prepare to receive the data
20513 
20514  // Compute the number of data (halo elements) to receive from each
20515  // processor and the displacements within each processor
20516 
20517  // Counter for the total number of halo elements within all processors
20518  unsigned counter_halo_ele_with_all_procs = 0;
20519 
20520  // Put in a vector the number of halo elements expected to receive
20521  // from each processor
20522  Vector<int> nhalo_elements_with_iproc(nproc);
20523  // Compute the number of total halo elements of (my_rank) this
20524  // processor with all other processors
20525  for (unsigned iproc = 0; iproc < nproc; iproc++)
20526  {
20527  // There are no halo/haloed elements with myself (my_rank
20528  // processor)
20529  if (iproc != my_rank)
20530  {
20531  // Get the number of halo elements with "iproc" processor
20532  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20533  // Copy the number of halo elements with "iproc" processor
20534  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20535  // Add the number of elements with this processor
20536  counter_halo_ele_with_all_procs+= n_halo_ele_iproc;
20537  } // if (iproc != my_rank)
20538 
20539  } // for (iproc < nproc)
20540 
20541  // The offsets of the flat package within each processor
20542  Vector<int> offset_halo_elements_with_iproc(nproc);
20543  offset_halo_elements_with_iproc[0] = 0;
20544  for (unsigned ip = 1; ip < nproc; ip++)
20545  {
20546  // Compute the offset to receive the values from each processor
20547  offset_halo_elements_with_iproc[ip] =
20548  offset_halo_elements_with_iproc[ip-1] +
20549  nhalo_elements_with_iproc[ip-1];
20550  } // for (ip < nproc)
20551 
20552  // The flat container to receive the new domains of the halo
20553  // elements in the current processor
20554 
20555  // The flat package where all the info. will be gather from the
20556  // other processors (the halo flat package)
20557  Vector<unsigned>
20558  new_domains_halo_flat_unsigned(counter_halo_ele_with_all_procs);
20559 
20560  // Perform the sending and receiving of information to and from all
20561  // processors
20562  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20563  &nhaloed_elements_with_iproc[0], // int *sendcnts
20564  &offset_haloed_elements_with_iproc[0], // int *sdispls
20565  MPI_UNSIGNED, // MPI_Datatype sendtype
20566  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20567  &nhalo_elements_with_iproc[0], // int *recvcnts
20568  &offset_halo_elements_with_iproc[0], // int *rdispls
20569  MPI_UNSIGNED, // MPI_Datatype recvtype
20570  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20571 
20572  // Once received the new domains for the halo elements, copy the
20573  // domains back to an easier to handle container (from the flat
20574  // package to the one with the different halo elements domains
20575  // within each processor)
20576  unsigned counter_new_domains_halo_ele = 0;
20577  for (unsigned iproc = 0; iproc < nproc; iproc++)
20578  {
20579  // There are no halo/haloed elements with myself (my_rank
20580  // processor)
20581  if (iproc != my_rank)
20582  {
20583  // Get the number of halo elements with "iproc"
20584  const unsigned ntmp_halo_elements_with_iproc =
20585  nhalo_elements_with_iproc[iproc];
20586  // Loop over the number of halo elements within "iproc" and copy
20587  // the elements from the flat package
20588  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20589  {
20590  // Copy the new domain of the halo elements from the flat
20591  // package to an easier to use container
20592  new_domains_halo_elements[iproc][i] =
20593  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20594  }
20595  } // if (iproc != my_rank)
20596  } // for (iproc < nproc)
20597 
20598  // The time to get domains of halo elements
20599  if (Print_timings_level_load_balance>1)
20600  {
20601  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20602  <<TimingHelpers::timer()-tt_start_get_domains_halo_elements
20603  << std::endl;
20604  }
20605 
20606  // =====================================================================
20607  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20608  // =====================================================================
20609 
20610  // =====================================================================
20611  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20612  // ELEMENTS
20613  // =====================================================================
20614 
20615  // Get the time to get FiniteElement versions from Generalised
20616  // halo(ed) elements
20617  double tt_start_get_fe_version_from_ge_halo_ed=0.0;
20618  if (Print_timings_level_load_balance>1)
20619  {
20620  tt_start_get_fe_version_from_ge_halo_ed=TimingHelpers::timer();
20621  }
20622 
20623  // The finite element storage for the halo elements
20624  Vector<Vector<FiniteElement*> > f_halo_element_pt(nproc);
20625  // The finite element storage for the haloed elements
20626  Vector<Vector<FiniteElement*> > f_haloed_element_pt(nproc);
20627  // Loop over the processors
20628  for (unsigned iproc = 0; iproc < nproc; iproc++)
20629  {
20630  // There are no halo(ed) elements with myself
20631  if (iproc != my_rank)
20632  {
20633  // Get the number of halo elements with the "iproc" processor
20634  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20635  // Get the halo elements with the "iproc" processor
20636  Vector<GeneralisedElement*> halo_element_pt_iproc =
20637  this->root_halo_element_pt(iproc);
20638  // Resize the finite element container
20639  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20640  // Loop over the halo elements
20641  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20642  {
20643  // Get the finite element
20644  FiniteElement* ele_pt =
20645  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20646  // Store the finite element version of the element
20647  f_halo_element_pt[iproc][ih] = ele_pt;
20648  } // for (ih < nhalo_ele_iproc)
20649 
20650  // Get the number of haloed elements with the "iproc" processor
20651  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20652  // Get the haloed elements with the "iproc" processor
20653  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20654  this->root_haloed_element_pt(iproc);
20655  // Resize the finite element container
20656  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20657  // Loop over the haloed elements
20658  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20659  {
20660  // Get the finite element
20661  FiniteElement* ele_pt =
20662  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20663  // Store the finite element version of the element
20664  f_haloed_element_pt[iproc][ihd] = ele_pt;
20665  } // for (ih < nhaloed_ele_iproc)
20666 
20667  } // if (iproc != my_rank)
20668 
20669  } // for (iproc < nproc)
20670 
20671  // The time to get FiniteElement versions from Generalised halo(ed)
20672  // elements
20673  if (Print_timings_level_load_balance>1)
20674  {
20675  oomph_info << "CPU for getting finite element versions from generalised halo(ed) elements (load balance) [2]: "
20676  <<TimingHelpers::timer()-tt_start_get_fe_version_from_ge_halo_ed
20677  << std::endl;
20678  }
20679 
20680  // =====================================================================
20681  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20682  // ELEMENTS
20683  // =====================================================================
20684 
20685  // =====================================================================
20686  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20687  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20688  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20689  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20690  // =====================================================================
20691 
20692  // Get the time to prepare elements to send to other processors
20693  double tt_start_prepare_element_to_send=0.0;
20694  if (Print_timings_level_load_balance>1)
20695  {
20696  tt_start_prepare_element_to_send=TimingHelpers::timer();
20697  }
20698 
20699  // Store the elements that will be sent to other processors
20700  Vector<Vector<FiniteElement*> > elements_to_send_pt(nproc);
20701 
20702  // Associate the nodes of each element with the processor the
20703  // element will live on
20704  std::map<Data*,std::set<unsigned> >
20705  processors_associated_with_data_before_load_balance;
20706 
20707  // Compute the elements that will be sent to other processor and
20708  // associate the nodes with the processor the element will live on
20709  unsigned nh_count3 = 0;
20710  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20711  {
20712  // Get the element
20713  FiniteElement *ele_pt = this->finite_element_pt(e);
20714  // Only work with nonhalo elements
20715  if (!(ele_pt->is_halo()))
20716  {
20717  // Get the new domain for the elment
20718  const unsigned element_domain =
20719  target_domain_for_local_non_halo_element[nh_count3++];
20720 
20721  // Include the element in the corresponding vector
20722  elements_to_send_pt[element_domain].push_back(ele_pt);
20723 
20724  // Get the number of nodes on the element
20725  const unsigned n_nodes = ele_pt->nnode();
20726  // Loop over the nodes
20727  for (unsigned j = 0; j < n_nodes; j++)
20728  {
20729  // Get each node of the element
20730  Node* node_pt = ele_pt->node_pt(j);
20731  // ... and associate it with element domains
20732  processors_associated_with_data_before_load_balance[node_pt].
20733  insert(element_domain);
20734 
20735  } // for (j < n_nodes)
20736 
20737  } // if (!(ele_pt->is_halo()))
20738 
20739  } // for (e < nelement_before_load_balance)
20740 
20741  // ... do the same for the halo elements (but do not add them to the
20742  // sending container since only the processor with the haloed
20743  // counterparts is in charge of that). Associate the nodes of the
20744  // halo elements with the processor they will live on
20745  for (unsigned iproc = 0; iproc < nproc; iproc++)
20746  {
20747  // There is no halo elements with myself
20748  if (iproc != my_rank)
20749  {
20750  // Get the number of halo elements with the "iproc" processor
20751  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20752  // Get the halo elements with the "iproc" processor
20753  Vector<GeneralisedElement*> halo_element_pt_iproc =
20754  this->root_halo_element_pt(iproc);
20755  // Loop over the halo elements with iproc
20756  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20757  {
20758  // Get the new domain for the halo element
20759  const unsigned element_domain =
20760  new_domains_halo_elements[iproc][ih];
20761 
20762  // Get the finite element
20763  FiniteElement* ele_pt =
20764  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20765 
20766  // Get the number of nodes on the halo element
20767  const unsigned n_nodes = ele_pt->nnode();
20768  // Loop over the nodes
20769  for (unsigned j = 0; j < n_nodes; j++)
20770  {
20771  // Get each node of the halo element
20772  Node* node_pt = ele_pt->node_pt(j);
20773 
20774  // ... and associate it with element domains
20775  processors_associated_with_data_before_load_balance[node_pt].
20776  insert(element_domain);
20777 
20778  } // for (j < n_nodes)
20779 
20780  } // for (ih < nhalo_ele_iproc)
20781 
20782  } // if (iproc != my_rank)
20783 
20784  } // for (iproc < nproc)
20785 
20786  // The time to prepare elements to send to other processors
20787  if (Print_timings_level_load_balance>1)
20788  {
20789  oomph_info << "CPU for preparing elements to send to other processors (load balance) [3]: "
20790  <<TimingHelpers::timer()-tt_start_prepare_element_to_send
20791  << std::endl;
20792  }
20793 
20794  // Now all the nodes are associated with the processor where the
20795  // element will live on. This is performed for the nonhalo and halo
20796  // elements
20797 
20798  // =====================================================================
20799  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20800  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20801  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20802  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20803  // =====================================================================
20804 
20805  // =====================================================================
20806  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
20807  // CURRENT PROCESSOR
20808  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
20809  // =====================================================================
20810 
20811  // Get the time to compute new local halo elements within all
20812  // processors
20813  double tt_start_compute_new_local_halo_elements=0.0;
20814  if (Print_timings_level_load_balance>1)
20815  {
20816  tt_start_compute_new_local_halo_elements=TimingHelpers::timer();
20817  }
20818 
20819  // Before sending the elements across compute the new local
20820  // halo/haloed elements of each processor. Each processor could have
20821  // elements that will be part of the new halo/haloed elements of
20822  // another processors, then these processors need to compute the
20823  // relations that may happen among these other processors
20824 
20825  // Example:
20826  // Processor 1 may have elements that will be sent to processor 3
20827  // and 4. These processors need to know about the new halo elements
20828  // betweeen them but at this moment only processor 1 can compute that
20829  // info., since it is the only one that currently has that info.
20830 
20831  // Store the new local-halo elements of each processor, the HALOED
20832  // elements are also stored in the container, only needs to INVERT
20833  // the indexes. For example, the HALO elements of processor 2 with
20834  // processor 3 are stored in new_local_halo_element_pt[2][3], and
20835  // the HALOED elements of processor 2 with processor 3 are stored in
20836  // new_local_halo_element_pt[3][2]. Notice that these are also the
20837  // halo elements of processor 3 with 2
20838 
20839  // How to identify the new local halo/haloed element: 1) Loop over
20840  // the element; 2) Only work with nonhalo elements; 3) If the
20841  // element is not assigned to the current processor (iproc) then
20842  // check; 4) Is one of its nodes assiociated to the iproc processor?
20843  // 5) If yes the element is a halo in the iproc processor whose
20844  // nonhalo counter part (haloed) lives in the domain assigned to the
20845  // element
20846  Vector<Vector<Vector<FiniteElement*> > > new_local_halo_element_pt(nproc);
20847 
20848  // Loop over the processors
20849  for (unsigned iproc = 0; iproc < nproc; iproc++)
20850  {
20851  // Resize the container
20852  new_local_halo_element_pt[iproc].resize(nproc);
20853 
20854  // Boolean to know which elements have been already added to the
20855  // new local halo scheme in "iproc"
20856  Vector<std::map<FiniteElement*,bool> > new_local_halo_already_added(nproc);
20857 
20858  // Go through all the elements and identify the new local halo
20859  // elements of "iproc"
20860  unsigned nh_count5 = 0;
20861  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20862  {
20863  // Get the element
20864  FiniteElement *ele_pt = this->finite_element_pt(e);
20865  // Only work with nonhalo elements
20866  if (!(ele_pt->is_halo()))
20867  {
20868  // Get the domain to which the current element is associated
20869  const unsigned ele_domain =
20870  target_domain_for_local_non_halo_element[nh_count5++];
20871  // If the current element is not associated to the "iproc"
20872  // processor then it could be a halo element
20873  if (ele_domain != iproc)
20874  {
20875  // Get the number of nodes
20876  const unsigned nnodes = ele_pt->nnode();
20877  // Loop over the nodes
20878  for (unsigned j = 0; j < nnodes; j++)
20879  {
20880  Node* node_pt = ele_pt->node_pt(j);
20881  // Check if the node is associated with the current
20882  // "iproc" processor
20883  std::set<unsigned>::iterator it =
20884  processors_associated_with_data_before_load_balance[node_pt].
20885  find(iproc);
20886  // If it is found then the element is a halo-element
20887  if (it!=
20888  processors_associated_with_data_before_load_balance[node_pt].
20889  end())
20890  {
20891  // Add the element as new local-halo element with the
20892  // "ele_domain" processor. The non-halo counterpart will
20893  // be located on "ele_domain" processor after sending
20894  // elements across
20895  if (!new_local_halo_already_added[ele_domain][ele_pt])
20896  {
20897  // The element is a halo element on "iproc" with
20898  // "ele_domain"
20899  new_local_halo_element_pt[iproc][ele_domain].
20900  push_back(ele_pt);
20901  // Mark as done
20902  new_local_halo_already_added[ele_domain][ele_pt] = true;
20903  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
20904  } // One of the nodes lies on an element on the current
20905  // "iproc" processor
20906  } // for (j < nnodes)
20907  } // if (ele_domain != iproc)
20908  } // if (!(ele_pt->is_halo()))
20909  } // for (e < nelement_before_load_balance)
20910 
20911  // Now do the same with the halo elements, we need to find those
20912  // halo elements that continue being halo elements but possibly
20913  // with/on another processor. The pair of processors where a
20914  // possible shared boundary is created needs to be notified.
20915 
20916  // Example
20917  //
20918  // ---------------* *---------------
20919  // | |* *| |
20920  // | |* *| |
20921  // | New domain |* *| New domain | * Mark the position
20922  // | proc 1 |* *| proc 3 | of halo elements
20923  // | |* *| |
20924  // | |* *| |
20925  // ---------------* *---------------
20926  // Proc 1 Proc 2
20927 
20928  // Processor 1: The halo elements on processor 1 continue being halo ON
20929  // PROCESSOR 1, but now WITH PROCESSOR 3
20930 
20931  // Processor 2: The halo elements on processor 2 continue being
20932  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
20933 
20934  // The current processor (my_rank) also needs to consider the halo
20935  // elements that will be halo elements of other processor with
20936  // another processor. The case of processor 2
20937 
20938  // Loop over all the halo elements in the current processor and
20939  // check if they will be halo with the "iproc" processor
20940  for (unsigned jproc = 0; jproc < nproc; jproc++)
20941  {
20942  // There are no halo elements with myself (the old halo elements
20943  // were halo in the "my_rank" processor)
20944  if (jproc != my_rank)
20945  {
20946  // Get the number of halo elements with the "jproc" processor
20947  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
20948  // Get the halo elements with the "jproc" processor
20949  Vector<GeneralisedElement*> halo_element_pt_jproc =
20950  this->root_halo_element_pt(jproc);
20951  // ... and check if any of those elements is a new halo
20952  // element with the "iproc" processor
20953  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
20954  {
20955  // Get the new domain for the halo element
20956  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
20957 
20958  // If the current element is not associated to the "iproc"
20959  // processor then it could be a halo element on "iproc" with
20960  // "ele_domain".
20961 
20962  // NOTE OUTDATE: Check if the halo element is going to be
20963  // sent to this processor (my_rank), if that is the case
20964  // then we don't need to add it to the set of new halo
20965  // elements with any other processor since any possible
20966  // shared boundary will be created when checking for the
20967  // intersection of the sent and received elements
20968 
20969  //if (ele_domain != iproc && ele_domain != my_rank)
20970 
20971  // NOTE UPDATE: Only check if the halo element is not going
20972  // to be part of the iproc processor, not required to avoid
20973  // those halo elements whose domain is the current rank
20974  // (my_rank). When the shared boundaries are computed, these
20975  // last elements can not create a shared boundary since no
20976  // haloed elements (that shared an edge) are found for
20977  // them. By considering also those halo elements whose new
20978  // domain is the current one (commenting "ele_domain !=
20979  // my_rank") the current processor can compute shared
20980  // boundaries with the iproc processor with help of its old
20981  // halo elements but that will become nonhalo elements, in
20982  // fact they will become haloed elements The halo element is
20983  // not sent to the "element_domain" processor and is not
20984  // passed to the array used to create the new shared
20985  // boundaries "new_shared_boundary_element_pt" because of
20986  // its halo condition
20987  if (ele_domain != iproc)
20988  {
20989  // Get the finite element
20990  FiniteElement* ele_pt =
20991  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
20992  // Get the number of nodes on the halo element
20993  const unsigned nnodes = ele_pt->nnode();
20994  // Loop over the nodes
20995  for (unsigned j = 0; j < nnodes; j++)
20996  {
20997  // Get each node of the halo element
20998  Node* node_pt = ele_pt->node_pt(j);
20999 
21000  // Check if the node is associated with the "iproc"
21001  // processor
21002  std::set<unsigned>::iterator it =
21003  processors_associated_with_data_before_load_balance[node_pt].
21004  find(iproc);
21005  // If it is found then the element is a halo-element
21006  if (it!=
21007  processors_associated_with_data_before_load_balance[node_pt].end())
21008  {
21009  // Add the element as new local-halo element with
21010  // the "ele_domain" processor. The non-halo
21011  // counterpart will be located on "ele_domain"
21012  // processor. Because this is a old-halo element it
21013  // will not be sent to the "element_domain" processor
21014  if (!new_local_halo_already_added[ele_domain][ele_pt])
21015  {
21016  // The element is a halo element on "iproc" with
21017  // "ele_domain"
21018  new_local_halo_element_pt[iproc][ele_domain].
21019  push_back(ele_pt);
21020  new_local_halo_already_added[ele_domain][ele_pt] = true;
21021 
21022  // Break the for of the nodes, the element has been
21023  // already added to the new_local_halo_element_pt
21024  // structure
21025  break;
21026 
21027  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21028 
21029  } // One of the nodes lies on an element belonging to
21030  // "iproc" processor
21031 
21032  } // for (j < nnodes)
21033 
21034  } // if (ele_domain != iproc)
21035 
21036  } // for (jh < n_halo_ele_jproc)
21037 
21038  } // if (jproc != my_rank) // The old halo elements are halo
21039  // with other processors except with "my_rank"
21040 
21041  } // for (jproc < nproc): This is the one that goes for the halo
21042  // elements in the current processor to find the new halo
21043  // elements
21044 
21045  } // for (iproc < nproc)
21046 
21047  // Get the time to compute new local halo elements within all
21048  // processors
21049  if (Print_timings_level_load_balance>1)
21050  {
21051  oomph_info << "CPU for computing new local halo elements (load balance) [4]: "
21052  <<TimingHelpers::timer()-tt_start_compute_new_local_halo_elements
21053  << std::endl;
21054  }
21055 
21056  // =====================================================================
21057  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21058  // CURRENT PROCESSOR
21059  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21060  // =====================================================================
21061 
21062  // =====================================================================
21063  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21064  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21065  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21066  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21067  // ELEMENTS IN THE RECEIVED PROCESSOR
21068  // =====================================================================
21069 
21070  // Get the time to compute new local shared boundary elements
21071  double tt_start_compute_new_local_shd_bnd_ele=0.0;
21072  if (Print_timings_level_load_balance>1)
21073  {
21074  tt_start_compute_new_local_shd_bnd_ele=TimingHelpers::timer();
21075  }
21076 
21077  // Store the new local-shared boundary elements and the face indexes
21078  // The halo elements and halo face indexes
21079  Vector<Vector<Vector<FiniteElement*> > >
21080  new_local_halo_shared_boundary_element_pt(nproc);
21081  Vector<Vector<Vector<unsigned> > >
21082  new_local_halo_shared_boundary_element_face_index(nproc);
21083 
21084  // Allocate enough memory for the containers
21085  for (unsigned iproc = 0; iproc < nproc; iproc++)
21086  {
21087  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21088  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21089  } // for (iproc < nproc)
21090 
21091  // Get the elements that create the new local-halo-shared
21092  // boundaries, mark them and identify the face that lies on the
21093  // shared boundary. The new local-halo-shared boundary elements are
21094  // actually a sub-set of the halo elements of each processor with in
21095  // each processor
21096  for (unsigned iproc = 0; iproc < nproc; iproc++)
21097  {
21098  // Star from jproc = iproc + 1 to avoid double creation of shared
21099  // boundary elements, any shared boundary element identified
21100  // between processor "iproc" and "jproc" is also established as
21101  // shared boundary element between processor "jproc" and "iproc"
21102  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21103  {
21104  this->get_shared_boundary_elements_and_face_indexes(
21105  new_local_halo_element_pt[iproc][jproc],
21106  new_local_halo_element_pt[jproc][iproc],
21107  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21108  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21109  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21110  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21111  } // for (jproc < nproc)
21112  } // for (iproc < nproc)
21113 
21114  // The time to compute new local shared boundary elements
21115  if (Print_timings_level_load_balance>1)
21116  {
21117  oomph_info << "CPU for computing new local shared boundary elements (load balance) [5]: "
21118  <<TimingHelpers::timer()-tt_start_compute_new_local_shd_bnd_ele
21119  << std::endl;
21120  }
21121 
21122  // =====================================================================
21123  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21124  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21125  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21126  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21127  // THE RECEIVED PROCESSOR
21128  // =====================================================================
21129 
21130  // =====================================================================
21131  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21132  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21133  // =====================================================================
21134 
21135  // Get the time to send the elements to their new processor in
21136  // charge
21137  double tt_start_send_elements_to_other_processors=0.0;
21138  if (Print_timings_level_load_balance>1)
21139  {
21140  tt_start_send_elements_to_other_processors=TimingHelpers::timer();
21141  }
21142 
21143  // Sort the nodes on shared boundaries so that they have the same
21144  // order on all the shared boundaries, this is required to know the
21145  // possible shared nodes among processors
21146  this->sort_nodes_on_shared_boundaries();
21147 
21148  // Store the received elements from each processor
21149  Vector<Vector<FiniteElement*> > received_elements_pt(nproc);
21150 
21151  // The haloed elements and haloed face indexes, these store the
21152  // haloed elements received from "iproc" but that are haloed with
21153  // "jproc". The elements are received from "iproc" which was the
21154  // processor that computed the haloed relation of the "my_rank"
21155  // processor with "jproc"
21156  Vector<Vector<Vector<FiniteElement*> > >
21157  new_received_haloed_shared_boundary_element_pt(nproc);
21158  Vector<Vector<Vector<unsigned> > >
21159  new_received_haloed_shared_boundary_element_face_index(nproc);
21160 
21161  // Container where to store the nodes on shared boundaries not
21162  // associated with the processor that receives the elements/nodes
21163  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21164  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
21165  other_proc_shd_bnd_node_pt(nproc);
21166  // Resize the container
21167  for (unsigned iproc = 0; iproc < nproc; iproc++)
21168  {
21169  // Resize the container
21170  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21171  for (unsigned jproc = 0; jproc < nproc; jproc++)
21172  {
21173  // Get the number of shared boundaries (OLD shared boundaries)
21174  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21175  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21176  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21177  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21178  } // for (jproc < nproc)
21179 
21180  } // for (iproc < nproc)
21181 
21182  // Store the global node names
21183  // global_node_name[x][ ][ ] Global node number
21184  // global_node_name[ ][x][ ] Global node names
21185  // global_node_name[ ][ ][x] Global node info.
21186  Vector<Vector<Vector<unsigned> > > global_node_names;
21187 
21188  // Creates a map between the node name and the index of the global
21189  // node so we can access all its node names
21190  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21191 
21192  // Store the global shared nodes pointers
21193  Vector<Node*> global_shared_node_pt;
21194 
21195  // Compute all the names of the nodes and fill in the
21196  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21197  // on this processor (my_rank) by looking over all their names
21198  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21199  global_node_names,
21200  node_name_to_global_index,
21201  global_shared_node_pt);
21202 
21203  // From the elements received from each processor, store the haloed
21204  // information of the element, it means, the processor with which it
21205  // is haloed and the haloed index with that processor
21206  Vector<Vector<std::map<unsigned,FiniteElement*> > >
21207  received_old_haloed_element_pt(nproc);
21208  // [x][][] : The receiver processor (the original processor)
21209  // [][x][] : The processor with which the receiver processor has
21210  // haloed elements
21211  // [][][x]: The haloed element number
21212 
21213  // Resize the container
21214  for (unsigned iproc = 0; iproc < nproc; iproc++)
21215  {
21216  received_old_haloed_element_pt[iproc].resize(nproc);
21217  } // for (iproc < nproc)
21218 
21219  // Go through all processors and send the corresponding elements to
21220  // each one
21221  for (unsigned iproc = 0; iproc < nproc; iproc++)
21222  {
21223  if (iproc != my_rank)
21224  {
21225  // -----------------------------------------------------------
21226  // Send (package) information of the elements
21227  // -----------------------------------------------------------
21228 
21229  // Keep track of the currently sent elements
21230  Vector<FiniteElement*> currently_sent_elements;
21231  // Keep track of the currently sent nodes to the iproc processor
21232  Vector<Node*> currently_sent_nodes;
21233 
21234  // Clear send and receive buffers
21235  Flat_packed_unsigneds.clear();
21236  Flat_packed_doubles.clear();
21237 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21238  Flat_packed_unsigneds_string.clear();
21239 #endif
21240 
21241  // Get the number of elements to send to iproc processor
21242  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21243 
21244  // The very first data of the flat package sent to processor
21245  // iproc is the number of elements that will be sent, this data
21246  // is used by the receiver processor to loop over the number of
21247  // expected elements to receive
21248  Flat_packed_unsigneds.push_back(nelements_to_send);
21249 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21250  std::stringstream junk;
21251  junk << "Number of elements to send from processor " << my_rank
21252  << " to processor " << iproc << ": ("
21253  << nelements_to_send << ")";
21254  Flat_packed_unsigneds_string.push_back(junk.str());
21255 #endif
21256 
21257  // Loop over the elements to sent
21258  for (unsigned e = 0; e < nelements_to_send; e++)
21259  {
21260  // Get the element to send
21261  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21262 
21263  // Get the current number of sent elements
21264  const unsigned ncurrently_sent_elements =
21265  currently_sent_elements.size();
21266 
21267  // Try to add the element
21268  const unsigned index_ele = try_to_add_element_pt_load_balance(
21269  currently_sent_elements, send_ele_pt);
21270 
21271  // Element needs to be added
21272  if (index_ele == ncurrently_sent_elements)
21273  {
21274  Flat_packed_unsigneds.push_back(1);
21275 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21276  Flat_packed_unsigneds_string.push_back("Element needs to be constructed");
21277 #endif
21278 
21279  // Get required info. related with the element
21280  get_required_elemental_information_load_balance_helper(
21281  iproc,
21282  f_haloed_element_pt,
21283  send_ele_pt);
21284 
21285  // Get the number of nodes in the element
21286  const unsigned nnodes = send_ele_pt->nnode();
21287 
21288  // Loop over the nodes in the element
21289  for (unsigned j = 0; j < nnodes; j++)
21290  {
21291  Node* node_pt = send_ele_pt->node_pt(j);
21292 
21293  // Package the info. of the nodes
21294  add_node_load_balance_helper(iproc, // The destination process
21295  f_halo_element_pt,
21296  currently_sent_nodes,
21297  node_pt);
21298 
21299  } // for (j < nnodes)
21300 
21301  } // if (index_ele == ncurrently_sent_elements)
21302  else
21303  {
21304  Flat_packed_unsigneds.push_back(0);
21305 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21306  Flat_packed_unsigneds_string.push_back("Element already exists");
21307 #endif
21308  Flat_packed_unsigneds.push_back(index_ele);
21309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21310  Flat_packed_unsigneds_string.push_back("Index of existing element");
21311 #endif
21312  } // else if (index_ele == ncurrently_sent_elements)
21313 
21314  } // for (e < nelements_to_send)
21315 
21316  // After storing the info. of the elements identify the indexes
21317  // of the "new_local_halo_shared_boundary_elements" in the
21318  // "currently_send_elements" vector, these elements will be
21319  // identified as "new_received_haloed_shared_boundary_elements"
21320  // on the "receiver" processor
21321 
21322  // Each processor has information of every other processor so we
21323  // need to send all the corresponding info. to the other
21324  // processors. Processor 1 may have information of the relation
21325  // (halo elements) between processor 3 and 4 say, so processor 1
21326  // needs to let know processor 3 and 4 what this relation is
21327  // (which are the shared-elements among these processors)
21328 
21329  for (unsigned jproc = 0; jproc < nproc; jproc++)
21330  {
21331  // Get the number of new local-halo shared boundary elements
21332  // between processor "jproc" and "iproc" (we invert the index
21333  // since we really want the haloed elements, those elements
21334  // that we have just sent)
21335  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21336  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21337 
21338  // The vector with the info. of the indexes
21339  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21340 
21341  // The number of found shared boundary elements in the sent
21342  // container (only consider the nonhalo elements)
21343  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21344  // The number of nonhalo elements in the new local halo shared
21345  // boundary elements
21346  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21347 
21348  // Loop over the local halo shared boundary elements between
21349  // processor jproc and iproc
21350  for (unsigned e = 0;
21351  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21352  {
21353  // Get the shared boundary element
21354  FiniteElement* shared_ele_pt =
21355  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21356 
21357  // Only consider the nonhalo elements since the halo
21358  // elements were no considered for sending
21359  if (!shared_ele_pt->is_halo())
21360  {
21361  nnon_halo_new_local_halo_shared_bound_ele++;
21362 
21363  // Now find the index on the currently sent elements
21364 
21365  // Get the current number of sent elements
21366  const unsigned ncurrently_sent_elements =
21367  currently_sent_elements.size();
21368  // Loop over the sent elements
21369  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21370  {
21371  FiniteElement* currently_sent_ele_pt =
21372  currently_sent_elements[ics];
21373 
21374  // Is this the element?
21375  if (currently_sent_ele_pt == shared_ele_pt)
21376  {
21377  // Store the index on the sent elements of the local
21378  // halo shared boundary element
21379  new_local_halo_shared_boundary_ele_index.push_back(ics);
21380  // Increase the number of found new local halo shared
21381  // bound element index
21382  nfound_new_local_halo_shared_bound_ele_index++;
21383  // We have found it, no need to further search
21384  break;
21385  } // if (currently_sent_ele_pt == shared_ele_pt)
21386 
21387  } // for (ics < ncurrently_sent_elements)
21388 
21389  } // if (!shared_ele_pt->is_halo())
21390 
21391  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21392 
21393 #ifdef PARANOID
21394  if (nfound_new_local_halo_shared_bound_ele_index !=
21395  nnon_halo_new_local_halo_shared_bound_ele)
21396  {
21397  std::ostringstream error_message;
21398  error_message
21399  << "Was only possible to identify ("
21400  << nfound_new_local_halo_shared_bound_ele_index << ") of ("
21401  << nnon_halo_new_local_halo_shared_bound_ele << ") shared "
21402  << "elements between\nprocessor ("<<iproc<<") and ("<<jproc<<") "
21403  << "when sending elements to processor ("<<iproc<<")\n\n";
21404  throw OomphLibError(error_message.str(),
21405  OOMPH_CURRENT_FUNCTION,
21406  OOMPH_EXCEPTION_LOCATION);
21407  }
21408 #endif
21409 
21410  // Send a flag for synchronisation issues
21411  Flat_packed_unsigneds.push_back(9999);
21412 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21413  std::stringstream junk;
21414  junk << "Flag for synchronisation 9999";
21415  Flat_packed_unsigneds_string.push_back(junk.str());
21416 #endif
21417 
21418  // Send the number of nonhalo new local-shared boundary
21419  // elements of processor "iproc" with processor "jproc"
21420  Flat_packed_unsigneds.push_back(nnon_halo_new_local_halo_shared_bound_ele);
21421 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21422  std::stringstream junk2;
21423  junk2 << "Number of new local halo shared boundary elements "
21424  << nnon_halo_new_local_halo_shared_bound_ele;
21425  Flat_packed_unsigneds_string.push_back(junk2.str());
21426 #endif
21427 
21428  // Send the indexes and the face indexes of the shared
21429  // boundary elements
21430  unsigned counter_nonhalo_sent = 0;
21431  // Loop over the local halo shared boundary elements between
21432  // processor jproc and iproc
21433  for (unsigned e = 0;
21434  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21435  {
21436  // Get the shared boundary element
21437  FiniteElement* shared_ele_pt =
21438  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21439 
21440  // Only consider the nonhalo elements since the halo
21441  // elements were no considered for sending
21442  if (!shared_ele_pt->is_halo())
21443  {
21444  // Get the index on the sent elements of the current
21445  // nonhalo shared boundary element
21446  const unsigned ele_index =
21447  new_local_halo_shared_boundary_ele_index[counter_nonhalo_sent++];
21448  // ... and get the face index
21449  const unsigned face_index =
21450  new_local_halo_shared_boundary_element_face_index[jproc][iproc][e];
21451 
21452  // Send the index on the sent elements of the new local
21453  // halo shared boundary element
21454  Flat_packed_unsigneds.push_back(ele_index);
21455 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21456  std::stringstream junk;
21457  junk << "The index of the halo shared boundary element "
21458  << ele_index;
21459  Flat_packed_unsigneds_string.push_back(junk.str());
21460 #endif
21461 
21462  // Send the face index of the new local halo shared boundary
21463  // element
21464  Flat_packed_unsigneds.push_back(face_index);
21465 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21466  std::stringstream junk2;
21467  junk2 << "The face index of the halo shared boundary element "
21468  << face_index;
21469  Flat_packed_unsigneds_string.push_back(junk2.str());
21470 #endif
21471 
21472  } // if (!shared_ele_pt->is_halo())
21473 
21474  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21475 
21476  } // for (jproc < nproc)
21477 
21478  // ----------------------------------------------------------
21479  // Send the info. perform the communications
21480  // ----------------------------------------------------------
21481  // Processor to which send the info.
21482  int send_proc = static_cast<int>(iproc);
21483  // Processor from which receive the info.
21484  int recv_proc = static_cast<int>(iproc);
21485  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21486 
21487  // ----------------------------------------------------------
21488  // Receive (unpackage) the info of the elements
21489  // ----------------------------------------------------------
21490 
21491  // Keep track of the currently created elements
21492  Vector<FiniteElement*> currently_created_elements;
21493  // Keep track of the currently created nodes
21494  Vector<Node*> currently_created_nodes;
21495 
21496  // Reset the counters
21497  Counter_for_flat_packed_doubles=0;
21498  Counter_for_flat_packed_unsigneds=0;
21499 
21500 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21501  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
21502  << " Number of elements need to be constructed "
21503  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
21504  << std::endl;
21505 #endif
21506 
21507  // Read the number of elements that need to be created
21508  const unsigned nelements_to_create =
21509  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21510 
21511  for (unsigned e = 0; e < nelements_to_create; e++)
21512  {
21513  // Create the element from received info. of "iproc"
21514  // processor on the current processor
21515  create_element_load_balance_helper(iproc,
21516  f_haloed_element_pt,
21517  received_old_haloed_element_pt,
21518  currently_created_elements,
21519  currently_created_nodes,
21520  other_proc_shd_bnd_node_pt,
21521  global_node_names,
21522  node_name_to_global_index,
21523  global_shared_node_pt);
21524  }
21525 
21526  // Copy the received elements from "iproc" processor
21527 
21528  // Number of received elements
21529  const unsigned nreceived_elements = currently_created_elements.size();
21530  received_elements_pt[iproc].resize(nreceived_elements);
21531  for (unsigned e = 0; e < nreceived_elements; e++)
21532  {received_elements_pt[iproc][e] = currently_created_elements[e];}
21533 
21534  // Go for the haloed elements received from processor "iproc"
21535  // but haloed with "jproc"
21536 
21537  // Allocate memory for the containers
21538  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21539  new_received_haloed_shared_boundary_element_face_index[iproc].resize(nproc);
21540 
21541  // Loop over the processors
21542  for (unsigned jproc = 0; jproc < nproc; jproc++)
21543  {
21544  // Read the synchronisation flag
21545  const unsigned synchronisation_flag =
21546  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21547 
21548  if (synchronisation_flag != 9999)
21549  {
21550  std::ostringstream error_message;
21551  error_message
21552  << "The synchronisation flag was not read, the\n"
21553  << "information sent between processor (" << my_rank << ") "
21554  << "and ("<< iproc << ")\nis no longer synchronised\n\n";
21555  throw OomphLibError(error_message.str(),
21556  OOMPH_CURRENT_FUNCTION,
21557  OOMPH_EXCEPTION_LOCATION);
21558  }
21559 
21560  // Read the number of elements that will be part of the new
21561  // received haloed shared boundary elements received from "iproc"
21562  // and haloed with "jproc"
21563  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21564  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21565 
21566  // Loop over the new received haloed shared boundary elements
21567  for (unsigned e = 0;
21568  e < niproc_jproc_new_received_haloed_shared_boundary_ele; e++)
21569  {
21570  // Read the index of the new received haloed shared boundary
21571  // ele with "jproc"
21572  const unsigned ele_index =
21573  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21574  // Read the face index for the new received haloed shared
21575  // boundary element
21576  const unsigned face_index =
21577  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21578 
21579  // Get the element
21580  FiniteElement* shared_ele_pt =
21581  currently_created_elements[ele_index];
21582 
21583  // Add the element to the new received-haloed shared
21584  // boundary elements. Received from "iproc" but haloed with
21585  // "jproc" processor
21586  new_received_haloed_shared_boundary_element_pt[iproc][jproc].
21587  push_back(shared_ele_pt);
21588  // Store the face index
21589  new_received_haloed_shared_boundary_element_face_index[iproc][jproc].
21590  push_back(face_index);
21591 
21592  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21593 
21594  } // for (jproc < nproc)
21595 
21596  } // if (iproc != my_rank)
21597 
21598  } // for (iproc < nproc)
21599 
21600  // The time to send the elements to their new processor in charge
21601  if (Print_timings_level_load_balance>1)
21602  {
21603  oomph_info << "CPU for sending elements to their new processors (load balance) [6]: "
21604  <<TimingHelpers::timer()-tt_start_send_elements_to_other_processors
21605  << std::endl;
21606  }
21607 
21608  // =====================================================================
21609  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21610  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21611  // =====================================================================
21612 
21613  // =====================================================================
21614  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21615  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21616  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21617  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21618  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21619  // ELEMENTS)
21620  // =====================================================================
21621 
21622  // Get the time to compute any additional shared boundary
21623  double tt_start_compute_additional_shared_boundaries=0.0;
21624  if (Print_timings_level_load_balance>1)
21625  {
21626  tt_start_compute_additional_shared_boundaries=TimingHelpers::timer();
21627  }
21628 
21629  // Store any additional elements that may create a shared boundary,
21630  // after sending elements from one to other processor check for any
21631  // new possible shared boundaries
21632  Vector<Vector<FiniteElement*> >
21633  tmp_group1_shared_boundary_element_pt(nproc);
21634  Vector<Vector<unsigned> >
21635  tmp_group1_shared_boundary_element_face_index(nproc);
21636  Vector<Vector<FiniteElement*> >
21637  tmp_group2_shared_boundary_element_pt(nproc);
21638  Vector<Vector<unsigned> >
21639  tmp_group2_shared_boundary_element_face_index(nproc);
21640 
21641  // Compute any additional shared boundaries by checking the
21642  // intersection between the received elements from each processor
21643  // and the elements just sent to that processor, the lowest
21644  // processors number loops over its received elements and the
21645  // highest loops over its sent elements (halo elements that have
21646  // become part of the domain now can create shared boundaries with
21647  // other processor)
21648 
21649  // Note: These additional shared boundaries may be created by the
21650  // elements that previously were halo but now have become part of
21651  // the processor (the received elements), and the elements that were
21652  // previously part of the processor but now have become halo (a
21653  // subset of the sent-elements)
21654 
21655  // Then these new shared boundaries come from the intersection of
21656  // the new-haloed elements (received elements) and the new-halo
21657  // elements (sent elements). These could be computed previously (in
21658  // the computing of the local new-halo and local new-haloed elements
21659  // usign the info. of the new domains for the old halo elements),
21660  // however, it was decided to perform the computation here in order to
21661  // avoid the identification of the old halo element that was part of a
21662  // shared boundary in the set of just received elements
21663  for (unsigned iproc = 0; iproc < nproc; iproc++)
21664  {
21665  if (my_rank < iproc)
21666  {
21667  // Lowest processor loops over the received elements
21668  this->get_shared_boundary_elements_and_face_indexes(
21669  received_elements_pt[iproc], elements_to_send_pt[iproc],
21670  tmp_group1_shared_boundary_element_pt[iproc],
21671  tmp_group1_shared_boundary_element_face_index[iproc],
21672  tmp_group2_shared_boundary_element_pt[iproc],
21673  tmp_group2_shared_boundary_element_face_index[iproc]);
21674 
21675  } // if (my_rank < iproc)
21676  else if (my_rank > iproc)
21677  {
21678  // Highest processor loops over the sent elements
21679  this->get_shared_boundary_elements_and_face_indexes(
21680  elements_to_send_pt[iproc], received_elements_pt[iproc],
21681  tmp_group1_shared_boundary_element_pt[iproc],
21682  tmp_group1_shared_boundary_element_face_index[iproc],
21683  tmp_group2_shared_boundary_element_pt[iproc],
21684  tmp_group2_shared_boundary_element_face_index[iproc]);
21685 
21686  } // else if (my_rank > iproc)
21687 
21688  } // for (iproc < nproc)
21689 
21690  // The time to compute any additional shared boundary
21691  if (Print_timings_level_load_balance>1)
21692  {
21693  oomph_info << "CPU for computing additional shared boundaries (load balance) [7]: "
21694  <<TimingHelpers::timer()-tt_start_compute_additional_shared_boundaries
21695  << std::endl;
21696  }
21697 
21698  // =====================================================================
21699  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21700  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21701  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21702  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21703  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21704  // ELEMENTS)
21705  // =====================================================================
21706 
21707  // =====================================================================
21708  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21709  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21710  // =====================================================================
21711 
21712  // Get the time to sort shared boundaries
21713  double tt_start_sort_shared_boundaries=0.0;
21714  if (Print_timings_level_load_balance>1)
21715  {
21716  tt_start_sort_shared_boundaries=TimingHelpers::timer();
21717  }
21718 
21719  // Once computed the elements that create the shared boundaries,
21720  // sort them so that the shared boundaries are created at the same
21721  // order in both processors that define the shared boundary
21722 
21723  // The order is like this
21724 
21725  // Lowest processors
21726  // 1) Shared boundary elements received from processors (local in
21727  // other processors)
21728  // 2) Local shared boundary elements (do not include halo elements)
21729  // 3) Shared boundary elements by intersection (already sorted)
21730 
21731  // Highest processors
21732  // 1) Local shared boundary elements (do not include halo elements)
21733  // 2) Shared boundary elements received from processors (local in
21734  // other processors)
21735  // 3) Shared boundary elements by intersection (already sorted)
21736 
21737  Vector<Vector<FiniteElement*> > new_shared_boundary_element_pt(nproc);
21738  Vector<Vector<unsigned> > new_shared_boundary_element_face_index(nproc);
21739  for (unsigned iproc = 0; iproc < nproc; iproc++)
21740  {
21741  // Lower processor
21742  if (my_rank < iproc)
21743  {
21744  // Copy the elements received from processor "jproc" but that
21745  // are haloed with "iproc" processor
21746  for (unsigned jproc = 0; jproc < nproc; jproc++)
21747  {
21748  // Can not receive elements from itself
21749  if (jproc != my_rank)
21750  {
21751  // Get the number of elements to copy from received processors
21752  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21753  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21754  for (unsigned e = 0;
21755  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21756  {
21757  // Get the element
21758  FiniteElement* ele_pt =
21759  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21760  // Get the face index
21761  const unsigned face_index =
21762  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21763 
21764  // Add the elements to the containers
21765  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21766  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21767 
21768  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
21769 
21770  } // if (jproc != my_rank)
21771 
21772  } // for (jproc < nproc)
21773 
21774  // Then the local shared haloed (invert the indexes to get the
21775  // haloed elements)
21776  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21777  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21778  for (unsigned e = 0;
21779  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21780  {
21781  // Get the element
21782  FiniteElement* ele_pt =
21783  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21784  // Get the face index
21785  const unsigned face_index =
21786  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21787 
21788  // Only include the element if it is nonhalo (this may be an
21789  // old halo element that helped to indentify a shared boundary
21790  // with iproc)
21791  if (!ele_pt->is_halo())
21792  {
21793  // Add the elements to the containers
21794  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21795  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21796  } // if (!ele_pt->is_halo())
21797 
21798  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21799 
21800  // ... and finally any additional shared boundary elements from
21801  // tmp_group1
21802  const unsigned ntmp_group1_shared_bound_ele_iproc =
21803  tmp_group1_shared_boundary_element_pt[iproc].size();
21804  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
21805  {
21806  // Get the element
21807  FiniteElement* ele_pt =
21808  tmp_group1_shared_boundary_element_pt[iproc][e];
21809  // Get the face index
21810  const unsigned face_index =
21811  tmp_group1_shared_boundary_element_face_index[iproc][e];
21812 
21813  // Add the elements to the containers
21814  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21815  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21816 
21817  } // for (e < ntmp_group1_shared_bound_ele_iproc)
21818 
21819  } // if (my_rank < iproc)
21820  // Highest processor
21821  else if (my_rank > iproc)
21822  {
21823  // Get the haloed elements first and then the elements received
21824  // from processor "jproc" but that are haloed with "iproc"
21825  // processor
21826 
21827  // Get the number of elements to copy from local elements
21828  // (invert the indexes to get the haloed elements)
21829  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21830  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21831  for (unsigned e = 0;
21832  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21833  {
21834  // Get the element
21835  FiniteElement* ele_pt =
21836  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21837  // Get the face index
21838  const unsigned face_index =
21839  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21840 
21841  // Only include the element if it is nonhalo (this may be an
21842  // old halo element that helped to indentify a shared boundary
21843  // with iproc)
21844  if (!ele_pt->is_halo())
21845  {
21846  // Add the elements to the containers
21847  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21848  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21849  } // if (!ele_pt->is_halo())
21850 
21851  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21852 
21853  for (unsigned jproc = 0; jproc < nproc; jproc++)
21854  {
21855  // Can not receive elements from itself
21856  if (jproc != my_rank)
21857  {
21858  // Then the received shared elements from "jproc" but haloed
21859  // with "iproc"
21860  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21861  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21862  for (unsigned e = 0;
21863  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21864  {
21865  // Get the element
21866  FiniteElement* ele_pt =
21867  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21868  // Get the face index
21869  const unsigned face_index =
21870  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21871 
21872  // Add the elements to the containers
21873  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21874  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21875 
21876  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
21877 
21878  } // if (jproc != my_rank)
21879 
21880  } // for (jproc < nproc)
21881 
21882  // ... and finally any additional shared boundary elements from
21883  // tmp_group2
21884  const unsigned ntmp_group2_shared_bound_ele_iproc =
21885  tmp_group2_shared_boundary_element_pt[iproc].size();
21886  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
21887  {
21888  // Get the element
21889  FiniteElement* ele_pt =
21890  tmp_group2_shared_boundary_element_pt[iproc][e];
21891  // Get the face index
21892  const unsigned face_index =
21893  tmp_group2_shared_boundary_element_face_index[iproc][e];
21894 
21895  // Add the elements to the containers
21896  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21897  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21898 
21899  } // for (e < ntmp_group2_shared_bound_ele_iproc)
21900 
21901  } // else if (my_rank > iproc)
21902 
21903  } // for (iproc < nproc)
21904 
21905  // The time to sort shared boundaries
21906  if (Print_timings_level_load_balance>1)
21907  {
21908  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
21909  <<TimingHelpers::timer()-tt_start_sort_shared_boundaries
21910  << std::endl;
21911  }
21912 
21913  // =====================================================================
21914  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21915  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21916  // =====================================================================
21917 
21918  // =====================================================================
21919  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
21920  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
21921  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
21922  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
21923  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
21924  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
21925  // THE ORIGINAL BOUNDARIES
21926  // =====================================================================
21927  // Finally, create the new shared boundaries
21928 
21929  // Get the time to create the new shared boundaries
21930  double tt_start_create_new_shared_boundaries=0.0;
21931  if (Print_timings_level_load_balance>1)
21932  {
21933  tt_start_create_new_shared_boundaries=TimingHelpers::timer();
21934  }
21935 
21936  // Compute the elements that will remain after deletion in the
21937  // curent processor. This is required to check if the new shared
21938  // boundaries crete a connection with any node of the elements in
21939  // the boundaries
21940 
21941  // Try to use as much information as possible
21942 
21943  // Storage for the elements in the processor
21944  std::set<FiniteElement*> element_in_processor_pt;
21945 
21946  // Loop over the old elements, those before sending/received
21947  // elements to/from other processors
21948  unsigned nh_count6 = 0;
21949  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21950  {
21951  // Get the element
21952  FiniteElement* ele_pt = backed_up_ele_pt[e];
21953  // Only work with nonhalo elements
21954  if (!(ele_pt->is_halo()))
21955  {
21956  // Is the element part of the new domain
21957  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
21958  {
21959  // Add the element to the set of elements in the processor
21960  element_in_processor_pt.insert(ele_pt);
21961 
21962  }
21963 
21964  } // if (!(ele_pt->is_halo()))
21965 
21966  } // for (e < nelement_before_load_balance)
21967 
21968  // Now include the received elements from the other processors
21969  // Loop over the processors
21970  for (unsigned iproc = 0; iproc < nproc; iproc++)
21971  {
21972  // No elements received from myself
21973  if (iproc != my_rank)
21974  {
21975  // Get the number of received elements with the "iproc"
21976  // processor
21977  const unsigned n_received_ele = received_elements_pt[iproc].size();
21978  for (unsigned ie = 0; ie < n_received_ele; ie++)
21979  {
21980  // Get the ie-th received element from processor iproc
21981  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
21982 
21983  // Include it in the set of elements in the processor
21984  element_in_processor_pt.insert(ele_pt);
21985 
21986  } // for (ie < nreceived_ele)
21987 
21988  } // if (iproc != my_rank)
21989 
21990  } // for (iproc < nproc)
21991 
21992  // Now create the shared boundaries
21993  create_new_shared_boundaries(element_in_processor_pt,
21994  new_shared_boundary_element_pt,
21995  new_shared_boundary_element_face_index);
21996 
21997  // The time to create the new shared boundaries
21998  if (Print_timings_level_load_balance>1)
21999  {
22000  oomph_info << "CPU for creating new shared boundaries (load balance) [9]: "
22001  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries
22002  << std::endl;
22003  }
22004 
22005  // =====================================================================
22006  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22007  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22008  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22009  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22010  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22011  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22012  // THE ORIGINAL BOUNDARIES
22013  // =====================================================================
22014 
22015  // =====================================================================
22016  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22017  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22018  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22019  // =====================================================================
22020 
22021  // Get the time to delete elements no longer belonging to the
22022  // processor
22023  double tt_start_delete_elements=0.0;
22024  if (Print_timings_level_load_balance>1)
22025  {
22026  tt_start_delete_elements=TimingHelpers::timer();
22027  }
22028 
22029  // Once computed the new shared boundaries delete the elements that
22030  // no longer belong to the processor (including the old halo
22031  // elements)
22032 
22033  // The procedure is similar to the one performed at the distribution
22034  // stage (src/generic/mesh.cc -- distribute() method)
22035 
22036  // Clean the storage for halo(ed) elements/nodes
22037  this->Halo_node_pt.clear();
22038  this->Root_halo_element_pt.clear();
22039 
22040  this->Haloed_node_pt.clear();
22041  this->Root_haloed_element_pt.clear();
22042 
22043  // Mark all the nodes as obsolete
22044  const unsigned nnodes = this->nnode();
22045  for (unsigned j = 0; j < nnodes; j++)
22046  {
22047  this->node_pt(j)->set_obsolete();
22048  }
22049 
22050  // Flush the mesh storage
22051  this->flush_element_storage();
22052 
22053  // Delete any storage of external elements and nodes
22054  this->delete_all_external_storage();
22055 
22056  // Clear external storage
22057  this->External_halo_node_pt.clear();
22058  this->External_halo_element_pt.clear();
22059 
22060  this->External_haloed_node_pt.clear();
22061  this->External_haloed_element_pt.clear();
22062 
22063  // Keep track of the deleted elements
22064  Vector<FiniteElement*> deleted_elements;
22065 
22066  // Delete the elements that no longer belong to the processor
22067  unsigned nh_count7 = 0;
22068  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22069  {
22070  FiniteElement* ele_pt = backed_up_ele_pt[e];
22071  // Only work with nonhalo elements
22072  if (!(ele_pt->is_halo()))
22073  {
22074  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22075  {
22076  // Add the element to the mesh
22077  this->add_element_pt(ele_pt);
22078  // Get the number of nodes on the element
22079  const unsigned nele_nodes = ele_pt->nnode();
22080  // Loop over the nodes of the element
22081  for (unsigned j = 0; j < nele_nodes; j++)
22082  {
22083  // Mark the node as non-obsolete
22084  ele_pt->node_pt(j)->set_non_obsolete();
22085  } // for (j < nele_nodes)
22086 
22087  } // The element belongs to the domain
22088  else
22089  {
22090  // Delete the element, but keep track of it
22091  deleted_elements.push_back(ele_pt);
22092  // Delete and point to null
22093  delete ele_pt;
22094  ele_pt = 0;
22095  }
22096 
22097  } // if (!(ele_pt->is_halo()))
22098  else
22099  {
22100  // If the element is halo, delete if but keep track of it
22101  deleted_elements.push_back(ele_pt);
22102  // Delete and point to null
22103  delete ele_pt;
22104  ele_pt = 0;
22105  }
22106 
22107  } // for (e < nelement_before_load_balance)
22108 
22109  // Now add the received elements from each processor
22110  for (unsigned iproc = 0; iproc < nproc; iproc++)
22111  {
22112  if (iproc != my_rank)
22113  {
22114  // Get the number of received elements with the "iproc"
22115  // processor
22116  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22117  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22118  {
22119  // Get the element and add it to the mesh
22120  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22121  // Add the element to the mesh
22122  this->add_element_pt(ele_pt);
22123  // Get the number of nodes on the element
22124  const unsigned nele_nodes = ele_pt->nnode();
22125  // Loop over the nodes of the element
22126  for (unsigned j = 0; j < nele_nodes; j++)
22127  {
22128  // Mark the node as non-obsolete
22129  ele_pt->node_pt(j)->set_non_obsolete();
22130  } // for (j < nele_nodes)
22131 
22132  } // for (ie < nreceived_ele)
22133 
22134  } // if (iproc != my_rank)
22135 
22136  } // for (iproc < nproc)
22137 
22138  // Now remove the obsolete nodes
22139  this->prune_dead_nodes();
22140 
22141  // The time to delete elements no longer belonging to the processor
22142  if (Print_timings_level_load_balance>1)
22143  {
22144  oomph_info << "CPU for deleting elements no longer belonging to this processor (load balance) [10]: "
22145  <<TimingHelpers::timer()-tt_start_delete_elements
22146  << std::endl;
22147  }
22148 
22149  // =====================================================================
22150  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22151  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22152  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22153  // =====================================================================
22154 
22155  // =====================================================================
22156  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22157  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22158  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22159  // ON EACH BOUNDARY
22160  // =====================================================================
22161 
22162  // Get the time to re-establish the halo(ed) information
22163  double tt_start_re_etablish_halo_ed_info=0.0;
22164  if (Print_timings_level_load_balance>1)
22165  {
22166  tt_start_re_etablish_halo_ed_info=TimingHelpers::timer();
22167  }
22168 
22169  // Prepare the data to re-establish the halo(ed) scheme
22170 
22171  // Sort the nodes on the new shared boundaries so that they have the
22172  // same order on all processors
22173  this->sort_nodes_on_shared_boundaries();
22174 
22175  // Before re-establish the halo and haloed elements save the number
22176  // of current elements in the boundaries, this will be useful to
22177  // re-establish the boundary elements. Notice that there may be
22178  // boundary elements with null pointers, since the element may no
22179  // longer belong to the current processor
22180  const unsigned tmp_nboundary = this->nboundary();
22181  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22182 
22183  // If there are regions, save the number of boundary-region elements
22184  Vector<Vector<unsigned> > ntmp_boundary_elements_in_region(tmp_nboundary);
22185  // Are there regions?
22186  const unsigned n_regions = this->nregion();
22187 
22188  // Loop over the boundaries
22189  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22190  {
22191  // Get the number of boundary elements
22192  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22193 
22194  // Resize the container
22195  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22196 
22197  // Loop over the regions
22198  for (unsigned rr = 0 ; rr < n_regions; rr++)
22199  {
22200  // Get the region id
22201  const unsigned region_id =
22202  static_cast<unsigned>(this->region_attribute(rr));
22203 
22204  // Store the number of element in the region (notice we are
22205  // using the region index not the region id to refer to the
22206  // region)
22207  ntmp_boundary_elements_in_region[ib][rr] =
22208  this->nboundary_element_in_region(ib, region_id);
22209 
22210  } // for (rr < n_regions)
22211 
22212  } // for (ib < tmp_nboundary)
22213 
22214  // Re-establish the halo(ed) scheme
22215  this->reset_halo_haloed_scheme();
22216 
22217  // Get the number of elements in the mesh after load balance
22218  const unsigned nelement_after_load_balance = this->nelement();
22219 
22220  // We need to reset boundary elements because we need to get rid of
22221  // the old boundary elements and stay only with the new ones
22222  this->reset_boundary_element_info(ntmp_boundary_elements,
22223  ntmp_boundary_elements_in_region,
22224  deleted_elements);
22225 
22226  // There is no need to re-set boundary coordinates since the
22227  // load-balanced mesh already has the correct information (the
22228  // boundary coordinate for each node was sent with the node
22229  // information)
22230 
22231  // We need to re-compute the number of segments on each boundary
22232  // after load balance. It may be possible that the boundary is now
22233  // split in more segments, or that previous gaps between the
22234  // segments have now dissapeared because the received elements
22235  // filled those gaps
22236 
22237  // In order to re-set the number of segments it is required to get
22238  // the face elements, attach them to create a contiguous
22239  // representation of the boundary (in segments possibly) and then
22240  // counter the number of segments. This can only be done after
22241  // restoring the boundary elements scheme (which has been done
22242  // above)
22243 
22244  // Set the number of segments for the boundaries with geom objects
22245  // associated. The correct value is not on the original mesh since
22246  // it is computed only when calling then
22247  // setup_boundary_coordinates() method (called only for those
22248  // boundaries with no geom object associated)
22249  for (unsigned b = 0; b < tmp_nboundary; b++)
22250  {
22251  if (this->boundary_geom_object_pt(b)!=0)
22252  {
22253  // Clear the boundary segment nodes storage
22254  this->flush_boundary_segment_node(b);
22255 
22256  // Dummy vector of nodes on segments
22257  Vector<Vector<Node*> > dummy_segment_node_pt;
22258 
22259  // Compute the new number of segments in the boundary
22260  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22261 
22262  // Get the number of segments from the vector of nodes
22263  const unsigned nsegments = dummy_segment_node_pt.size();
22264 
22265  // Set the number of segments for the storing of the nodes
22266  // associated to the segments
22267  this->set_nboundary_segment_node(b, nsegments);
22268  } // if (this->boundary_geom_object_pt(b)!=0)
22269 
22270  } // for (b < n_boundary)
22271 
22272  // The time to re-establish the halo(ed) information
22273  if (Print_timings_level_load_balance>1)
22274  {
22275  oomph_info << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22276  <<TimingHelpers::timer()-tt_start_re_etablish_halo_ed_info
22277  << std::endl;
22278  }
22279 
22280  // =====================================================================
22281  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22282  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22283  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22284  // BOUNDARY
22285  // =====================================================================
22286 
22287  if (Print_timings_level_load_balance>1)
22288  {
22289  oomph_info <<"CPU for load balance [n_ele_before="
22290  <<nelement_before_load_balance<<", n_ele_after="
22291  <<nelement_after_load_balance<<"]: "
22292  <<TimingHelpers::timer()-t_start_overall_load_balance
22293  << std::endl;
22294  }
22295 
22296  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22297 
22298  }
22299 
22300  //======================================================================
22301  /// Use the first and second group of elements to find the
22302  /// intersection between them to get the shared boundary
22303  /// elements from the first and second group
22304  //======================================================================
22305  template <class ELEMENT>
22308  const Vector<FiniteElement*> &first_element_pt,
22309  const Vector<FiniteElement*> &second_element_pt,
22310  Vector<FiniteElement*> &first_shared_boundary_element_pt,
22311  Vector<unsigned> &first_shared_boundary_element_face_index,
22312  Vector<FiniteElement*> &second_shared_boundary_element_pt,
22313  Vector<unsigned> &second_shared_boundary_element_face_index)
22314  {
22315  // 1) Compare their faces (nodes) and if they match then they are
22316  // part of a shared boundary
22317  // 2) Save the first and second group of elements that give rise to
22318  // the shared boundary, also include the face index
22319 
22320  // Get the number of elements on the first group
22321  const unsigned nfirst_element = first_element_pt.size();
22322  // Loop over the elements in the first group
22323  for (unsigned ef = 0; ef < nfirst_element; ef++)
22324  {
22325  // Get the element
22326  FiniteElement* fele_pt = first_element_pt[ef];
22327  // Check if the element is halo
22328  bool first_ele_is_halo = false;
22329  if (fele_pt->is_halo())
22330  {
22331  first_ele_is_halo = true;
22332  }
22333  // Get each of the faces
22334  for (unsigned ifface = 0; ifface < 3; ifface++)
22335  {
22336  Vector<Node*> first_face(2);
22337  if (ifface == 0)
22338  {
22339  first_face[0] = fele_pt->node_pt(1);
22340  first_face[1] = fele_pt->node_pt(2);
22341  }
22342  else if (ifface == 1)
22343  {
22344  first_face[0] = fele_pt->node_pt(2);
22345  first_face[1] = fele_pt->node_pt(0);
22346  }
22347  else if (ifface == 2)
22348  {
22349  first_face[0] = fele_pt->node_pt(0);
22350  first_face[1] = fele_pt->node_pt(1);
22351  }
22352 
22353  // Now check each of the faces with the faces on the second
22354  // elements
22355 
22356  // Get the number of elements on the second group
22357  const unsigned nsecond_element = second_element_pt.size();
22358  // Loop over the elements in the second group
22359  for (unsigned es = 0; es < nsecond_element; es++)
22360  {
22361  // Get the element
22362  FiniteElement* sele_pt = second_element_pt[es];
22363  // Check if the element is halo
22364  bool second_ele_is_halo = false;
22365  if (sele_pt->is_halo())
22366  {
22367  second_ele_is_halo = true;
22368  }
22369  // Now check whether both elements are halo, if that is the
22370  // case then we go for the next elements. We can not look for
22371  // shared boundaries between halo elements since other
22372  // processors, those with the nonhalo counterpart of the
22373  // elements, are in charge of creating those shared boundaries
22374  if (!(first_ele_is_halo && second_ele_is_halo))
22375  {
22376  // Get each of the faces
22377  for (unsigned isface = 0; isface < 3; isface++)
22378  {
22379  Vector<Node*> second_face(2);
22380  if (isface == 0)
22381  {
22382  second_face[0] = sele_pt->node_pt(1);
22383  second_face[1] = sele_pt->node_pt(2);
22384  }
22385  else if (isface == 1)
22386  {
22387  second_face[0] = sele_pt->node_pt(2);
22388  second_face[1] = sele_pt->node_pt(0);
22389  }
22390  else if (isface == 2)
22391  {
22392  second_face[0] = sele_pt->node_pt(0);
22393  second_face[1] = sele_pt->node_pt(1);
22394  }
22395 
22396  // Now check for any intersection among first and second
22397  // faces
22398  if (first_face[0] == second_face[0] &&
22399  first_face[1] == second_face[1])
22400  {
22401  // Save the elements on the corresponding containers
22402  first_shared_boundary_element_pt.push_back(fele_pt);
22403  // .. and the face index
22404  first_shared_boundary_element_face_index.push_back(ifface);
22405 
22406  // Save the elements on the corresponding containers
22407  second_shared_boundary_element_pt.push_back(sele_pt);
22408  // .. and the face index
22409  second_shared_boundary_element_face_index.push_back(isface);
22410 
22411  // Break the loop over the faces of the first elements
22412  // and the first elements, we need to continue looking
22413  // on the next face of the first elements
22414 
22415  // Increase the indexes to force breaking the loop
22416  isface = 3;
22417  es = nsecond_element;
22418 
22419  }
22420  // Check for intersection with the reversed case too
22421  else if (first_face[0] == second_face[1] &&
22422  first_face[1] == second_face[0])
22423  {
22424  // Save the elements on the corresponding containers
22425  first_shared_boundary_element_pt.push_back(fele_pt);
22426  // .. and the face index
22427  first_shared_boundary_element_face_index.push_back(ifface);
22428 
22429  // Save the elements on the corresponding containers
22430  second_shared_boundary_element_pt.push_back(sele_pt);
22431  // .. and the face index
22432  second_shared_boundary_element_face_index.push_back(isface);
22433 
22434  // Break the loop over the faces of the first elements
22435  // and the first elements, we need to continue looking
22436  // on the next face of the first elements
22437 
22438  // Increase the indexes to force breaking the loop
22439  isface = 3;
22440  es = nsecond_element;
22441  }
22442 
22443  } // for (isface < 3)
22444 
22445  } // if (!(first_ele_is_halo && second_ele_is_halo))
22446 
22447  } // for (es < nsecond_element)
22448 
22449  } // for (ifface < 3)
22450 
22451  } // for (ef < nfirst_element)
22452 
22453  }
22454 
22455  //======================================================================
22456  /// \short Creates the new shared boundaries, this method is also in
22457  /// charge of computing the shared boundaries ids of each processor
22458  /// and send that info. to all the processors
22459  //======================================================================
22460  template <class ELEMENT>
22462  create_new_shared_boundaries(std::set<FiniteElement*>
22463  &element_in_processor_pt,
22464  Vector<Vector<FiniteElement*> >
22465  &new_shared_boundary_element_pt,
22466  Vector<Vector<unsigned> >
22467  &new_shared_boundary_element_face_index)
22468  {
22469  // Get the number of processors
22470  const unsigned nproc = this->communicator_pt()->nproc();
22471  // Get the rank of the current processor
22472  const unsigned my_rank = this->communicator_pt()->my_rank();
22473 
22474  // ================================================================
22475  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22476  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22477  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22478  // SAME EDGE (INTERNAL BOUNDARIES)
22479  // ================================================================
22480 
22481  // Get the time to get edges from shared boundary face elements
22482  double tt_start_get_edges_from_shd_bnd_face_ele=0.0;
22483  if (Print_timings_level_load_balance>2)
22484  {
22485  tt_start_get_edges_from_shd_bnd_face_ele=TimingHelpers::timer();
22486  }
22487 
22488  // Face elements that create the shared boundaries (unsorted)
22489  Vector<Vector<FiniteElement*> > tmp_unsorted_face_ele_pt(nproc);
22490  // The elements from where the face element was created
22491  Vector<Vector<FiniteElement*> > tmp_unsorted_ele_pt(nproc);
22492  // The face index of the bulk element from where was created the
22493  // face element
22494  Vector<Vector<int> > tmp_unsorted_face_index_ele(nproc);
22495 
22496  // Store the current edges lying on boundaries (this will help for
22497  // any edge of a shared boundary lying on an internal boundary)
22498  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22499 
22500  // Compute the edges on the other boundaries
22501  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22502 
22503  // Mark those edges (pair of nodes overlapped by a shared boundary)
22504  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
22505 
22506  // Associate every found edge (face element) on the shared boundary
22507  // with an original boundary only if the edge (face element) lies
22508  // (overlaps) on an original boundary, it may happen only for
22509  // internal boundaries
22510  Vector<Vector<int> > tmp_edge_boundary(nproc);
22511 
22512  // Get the face elements from the shared boundary elements with in
22513  // each processor
22514  for (unsigned iproc = 0; iproc < nproc; iproc++)
22515  {
22516  // There are no shared boundary elements with myself
22517  if (iproc != my_rank)
22518  {
22519  // Get the number of shared boundary elements with in "iproc"
22520  // processor
22521  const unsigned n_shared_bound_ele =
22522  new_shared_boundary_element_pt[iproc].size();
22523 
22524  // Avoid to create repeated face elements, compare the nodes on
22525  // the edges of the face elements
22526  Vector<std::pair<Node*, Node*> > done_faces;
22527 
22528  // Count the number of repeated faces
22529  unsigned nrepeated_faces = 0;
22530 
22531  // Loop over the shared boundary elements with the iproc
22532  // processor
22533  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22534  {
22535  // Get the bulk element
22536  FiniteElement* bulk_ele_pt =
22537  new_shared_boundary_element_pt[iproc][iele];
22538 
22539  // Get the face index
22540  int face_index =
22541  static_cast<int>(new_shared_boundary_element_face_index[iproc][iele]);
22542 
22543  // Create the face element
22544  FiniteElement* tmp_ele_pt =
22545  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
22546 
22547  // Before adding the face element to the vector check that is
22548  // not has been previously created
22549  bool done_face = false;
22550 
22551  // Get the number of nodes on the face element and get the first
22552  // and last node
22553  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22554  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22555  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22556 
22557  // Get the number of already done face elements
22558  const unsigned ndone_faces = done_faces.size();
22559  // Loop over the already visited face elements
22560  for (unsigned n = 0; n < ndone_faces; n++)
22561  {
22562  Node* first_done_face_node_pt = done_faces[n].first;
22563  Node* second_done_face_node_pt = done_faces[n].second;
22564  if (first_face_node_pt == first_done_face_node_pt &&
22565  last_face_node_pt == second_done_face_node_pt)
22566  {
22567  done_face = true;
22568  nrepeated_faces++;
22569  break;
22570  }
22571  // Check for the reversed case
22572  else if (first_face_node_pt == second_done_face_node_pt &&
22573  last_face_node_pt == first_done_face_node_pt)
22574  {
22575  done_face = true;
22576  nrepeated_faces++;
22577  break;
22578  }
22579 
22580  } // for (n < ndone_faces)
22581 
22582  // Only include the faces that are not repeated
22583  if (!done_face)
22584  {
22585  // Add the face element in the vector
22586  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22587  // Add the bulk element to the vector
22588  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22589  // Add the face index to the vector
22590  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22591  // Include the nodes in the done nodes vector
22592  std::pair<Node*, Node*> tmp_edge =
22593  std::make_pair(first_face_node_pt, last_face_node_pt);
22594  // Push the edge
22595  done_faces.push_back(tmp_edge);
22596 
22597  // Associate the face element with a boundary (if that is
22598  // the case)
22599  int edge_boundary_id = -1;
22600  std::map<std::pair<Node*,Node*>, unsigned >::iterator it;
22601  it = elements_edges_on_boundary.find(tmp_edge);
22602  // If the edges lie on a boundary then get the boundary id
22603  // on which the edges lie
22604  if (it != elements_edges_on_boundary.end())
22605  {
22606  // Assign the internal boundary id associated with the
22607  // edge
22608  edge_boundary_id = (*it).second;
22609  // Mark the edge as overlapped
22610  overlapped_edge[tmp_edge] = true;
22611  // Also include the reversed version of the edge
22612  std::pair<Node*, Node*> rev_tmp_edge =
22613  std::make_pair(last_face_node_pt, first_face_node_pt);
22614  // Mark the reversed version of the edge as overlapped
22615  overlapped_edge[rev_tmp_edge] = true;
22616  }
22617  else
22618  {
22619  // Look for the reversed version
22620  std::pair<Node*,Node*> rtmp_edge =
22621  std::make_pair(last_face_node_pt, first_face_node_pt);
22622  it = elements_edges_on_boundary.find(rtmp_edge);
22623  if (it != elements_edges_on_boundary.end())
22624  {
22625  // Assign the internal boundary id associated with the
22626  // edge
22627  edge_boundary_id = (*it).second;
22628  // Mark the edge as overlapped
22629  overlapped_edge[rtmp_edge] = true;
22630  // Mark the reversed version (normal) of the edge as
22631  // overlapped
22632  overlapped_edge[tmp_edge] = true;
22633  }
22634  }
22635  // Associate the edge with a boundary
22636  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22637  } // if (!done_face)
22638  else
22639  {
22640  // Delete the repeated face elements
22641  delete tmp_ele_pt;
22642  tmp_ele_pt = 0;
22643  }
22644 
22645  } // for (iele < n_shared_bound_ele)
22646 
22647  } // if (iproc != my_rank)
22648 
22649  } // for (iproc < nproc)
22650 
22651  // The time to get edges from shared boundary face elements
22652  if (Print_timings_level_load_balance>2)
22653  {
22654  oomph_info << "CPU for getting edges from shared boundary face elements (load balance) [9.1]: "
22655  <<TimingHelpers::timer()-tt_start_get_edges_from_shd_bnd_face_ele
22656  << std::endl;
22657  }
22658 
22659  // ================================================================
22660  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22661  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22662  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22663  // SAME EDGE (INTERNAL BOUNDARIES)
22664  // ================================================================
22665 
22666  // ================================================================
22667  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22668  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22669  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22670  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22671  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22672  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22673  // ================================================================
22674 
22675  // Get the time to sort shared face elements
22676  double tt_start_sort_shared_face_elements=0.0;
22677  if (Print_timings_level_load_balance>2)
22678  {
22679  tt_start_sort_shared_face_elements=TimingHelpers::timer();
22680  }
22681 
22682  // -----------------------------------------------------------------
22683  // Before continuing we need to ensured that the face elements are
22684  // stored in the same order in all processors. Sort them starting
22685  // from the face element with the bottom-left node coordinate
22686 
22687  // Face elements that create the shared boundaries (unsorted)
22688  Vector<Vector<FiniteElement*> > unsorted_face_ele_pt(nproc);
22689  // The elements from where the face element was created
22690  Vector<Vector<FiniteElement*> > unsorted_ele_pt(nproc);
22691  // The face index of the bulk element from where was created the
22692  // face element
22693  Vector<Vector<int> > unsorted_face_index_ele(nproc);
22694  // Associate every found edge on the shared boundary with an
22695  // original boundary only if the edge lies on an original boundary,
22696  // it may happen only for internal boundaries
22697  Vector<Vector<int> > edge_boundary(nproc);
22698 
22699  // For each face element, mark if the element should be considered
22700  // in its inverted way to fullfill with the bottom-left node to be
22701  // the first (left) node. First get the status of each element and
22702  // when they get sorted copy the values across
22703  std::vector<std::vector<bool> > tmp_treat_as_inverted(nproc);
22704  // Vector to store the status of the sorted face elements based on
22705  // the bottom-left condition
22706  std::vector<std::vector<bool> > treat_as_inverted(nproc);
22707 
22708  // Get the bottom-left node of each face element and sort them
22709  // starting from the face element with the bottom-left node
22710 
22711  // Loop over the processors
22712  for (unsigned iproc = 0; iproc < nproc; iproc++)
22713  {
22714  // There are no shared face elements with myself
22715  if (iproc != my_rank)
22716  {
22717  // Get the number of unsorted face elements
22718  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22719  // Store the centroid of the face element. Perform the sorting
22720  // based on the bottom-left centroid of each face element
22721  Vector<Vector<double> > centroid_vertices(n_face_ele);
22722 
22723  // Resize the storage for the treating as inverted face element
22724  // storage
22725  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22726 
22727  // Loop over the face elements associated with the iproc
22728  // processor
22729  for (unsigned e = 0; e < n_face_ele; e++)
22730  {
22731  // Get the face element
22732  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22733  // Get the number of nodes of the face element
22734  const unsigned n_node = face_ele_pt->nnode();
22735  Vector<double> bottom_left(2);
22736  // Assign as the bottom-left node the first node
22737  // Get the node
22738  Node* node_pt = face_ele_pt->node_pt(0);
22739  bottom_left[0] = node_pt->x(0);
22740  bottom_left[1] = node_pt->x(1);
22741  // Set as not treat as inverted element
22742  tmp_treat_as_inverted[iproc][e] = false;
22743  // Loop over the nodes to get the bottom-left vertex of all
22744  // the nodes
22745  for (unsigned n = 1; n < n_node; n++)
22746  {
22747  // Get the node
22748  Node* node_pt = face_ele_pt->node_pt(n);
22749  if (node_pt->x(1) < bottom_left[1])
22750  {
22751  bottom_left[0] = node_pt->x(0);
22752  bottom_left[1] = node_pt->x(1);
22753  // The first node is no longer the bottom-left node, we
22754  // need to treat the element as inverted
22755  tmp_treat_as_inverted[iproc][e] = true;
22756  } // if (node_pt->x(1) < bottom_left[1])
22757  else if (node_pt->x(1) == bottom_left[1])
22758  {
22759  if (node_pt->x(0) < bottom_left[0])
22760  {
22761  bottom_left[0] = node_pt->x(0);
22762  bottom_left[1] = node_pt->x(1);
22763  // The first node is no longer the bottom-left node, we
22764  // need to treat the element as inverted
22765  tmp_treat_as_inverted[iproc][e] = true;
22766  } // if (node_pt->x(0) < bottom_left[0])
22767  } // else if (node_pt->x(1) == bottom_left[1])
22768 
22769  } // for (n < n_node
22770 
22771  // Resize the container
22772  centroid_vertices[e].resize(2);
22773  // Add the centroid of the face element
22774  centroid_vertices[e][0] =
22775  (face_ele_pt->node_pt(0)->x(0) +
22776  face_ele_pt->node_pt(n_node-1)->x(0))*0.5;
22777  centroid_vertices[e][1] =
22778  (face_ele_pt->node_pt(0)->x(1) +
22779  face_ele_pt->node_pt(n_node-1)->x(1))*0.5;
22780 
22781  } // for (e < n_face_ele)
22782 
22783  // Sort the face elements based on their bottom-left node
22784  unsigned n_sorted_bottom_left = 0;
22785  // Keep track of the already sorted face elements
22786  std::vector<bool> done_face(n_face_ele, false);
22787 
22788  // Loop until all face elements have been sorted
22789  while (n_sorted_bottom_left < n_face_ele)
22790  {
22791  // The index of the next bottom-left face element
22792  unsigned index = 0;
22793  Vector<double> current_bottom_left(2);
22794  for (unsigned e = 0; e < n_face_ele; e++)
22795  {
22796  // Get the first not done face element
22797  if (!done_face[e])
22798  {
22799  // Store the first not done
22800  current_bottom_left[0] = centroid_vertices[e][0];
22801  current_bottom_left[1] = centroid_vertices[e][1];
22802  // Set the index
22803  index = e;
22804  // Break
22805  break;
22806  } // if (!done_face[e])
22807 
22808  } // for (e < n_face_ele)
22809 
22810  // Loop over all the other nondone face elements
22811  for (unsigned e = index + 1; e < n_face_ele; e++)
22812  {
22813  // Get the first not done face element
22814  if (!done_face[e])
22815  {
22816  if (centroid_vertices[e][1] < current_bottom_left[1])
22817  {
22818  // Re-set the current bottom left vertex
22819  current_bottom_left[0] = centroid_vertices[e][0];
22820  current_bottom_left[1] = centroid_vertices[e][1];
22821  // Re-assign the index
22822  index = e;
22823  } // if (centroid_vertices[e][1] < current_bottom_left[1])
22824  else if (centroid_vertices[e][1] == current_bottom_left[1])
22825  {
22826  if (centroid_vertices[e][0] < current_bottom_left[0])
22827  {
22828  // Re-set the current bottom left vertex
22829  current_bottom_left[0] = centroid_vertices[e][0];
22830  current_bottom_left[1] = centroid_vertices[e][1];
22831  // Re-assign the index
22832  index = e;
22833  } // if (centroid_vertices[e][0] < current_bottom_left[0])
22834 
22835  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
22836 
22837  } // if (!done_face[e])
22838 
22839  } // for (e < n_face_ele)
22840 
22841  // The face element
22842  unsorted_face_ele_pt[iproc].
22843  push_back(tmp_unsorted_face_ele_pt[iproc][index]);
22844  // The boundary element
22845  unsorted_ele_pt[iproc].
22846  push_back(tmp_unsorted_ele_pt[iproc][index]);
22847  // The face index
22848  unsorted_face_index_ele[iproc].
22849  push_back(tmp_unsorted_face_index_ele[iproc][index]);
22850  // The edge boundary associated to the face element
22851  edge_boundary[iproc].
22852  push_back(tmp_edge_boundary[iproc][index]);
22853  // The treat as inverted condition
22854  treat_as_inverted[iproc].
22855  push_back(tmp_treat_as_inverted[iproc][index]);
22856 
22857  // Mark the face element as sorted (done or visited)
22858  done_face[index] = true;
22859 
22860  // Increase the number of sorted bottom-left face elements
22861  n_sorted_bottom_left++;
22862 
22863  } // while (n_sorted_bottom_left < n_face_ele)
22864 
22865 #ifdef PARANOID
22866  // Get the number of face elements sorted with the bottom-left
22867  // condition
22868  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
22869 
22870  if (tmp_n_face_ele != n_face_ele)
22871  {
22872  std::ostringstream error_stream;
22873  error_stream
22874  << "The number of face elements before sorting them starting\n"
22875  << "from their bottom-left vertex is different from the number\n"
22876  << "of face elements after the sorting\n"
22877  << "N. ele before sorting: (" << n_face_ele << ")\n"
22878  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
22879  throw OomphLibError(error_stream.str(),
22880  "RefineableTriangleMesh::create_new_shared_boundaries()",
22881  OOMPH_EXCEPTION_LOCATION);
22882  }
22883 #endif
22884 
22885  } // if (iproc != my_rank)
22886 
22887  } // for (iproc < nproc)
22888 
22889  // The time to sort shared face elements
22890  if (Print_timings_level_load_balance>2)
22891  {
22892  oomph_info << "CPU for sorting shared boundary face elements (load balance) [9.2]: "
22893  <<TimingHelpers::timer()-tt_start_sort_shared_face_elements
22894  << std::endl;
22895  }
22896 
22897  // ================================================================
22898  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
22899  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
22900  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
22901  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
22902  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22903  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22904  // ================================================================
22905 
22906  // ================================================================
22907  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22908  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22909  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22910  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22911  // IS THE CASE)
22912  // ================================================================
22913 
22914  // Get the time to compute the valency of each node
22915  double tt_start_compute_valency_of_nodes=0.0;
22916  if (Print_timings_level_load_balance>2)
22917  {
22918  tt_start_compute_valency_of_nodes=TimingHelpers::timer();
22919  }
22920 
22921  // Stores the global-degree of each node
22922  std::map<Node*, unsigned> global_node_degree;
22923 
22924  // Get the global degree (valency) of each node
22925  compute_shared_node_degree_helper(unsorted_face_ele_pt,
22926  global_node_degree);
22927 
22928  // The time to compute the valency of each node
22929  if (Print_timings_level_load_balance>2)
22930  {
22931  oomph_info << "CPU for computing the valency of nodes (load balance) [9.3]: "
22932  <<TimingHelpers::timer()-tt_start_compute_valency_of_nodes
22933  << std::endl;
22934  }
22935 
22936  // ================================================================
22937  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22938  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22939  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22940  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22941  // IS THE CASE)
22942  // ================================================================
22943 
22944  // ================================================================
22945  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22946  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22947  // ================================================================
22948 
22949  // Get the time to compute nodes on non overlapped shared boundaries
22950  double tt_start_nodes_on_non_overlapped_shd_bnd=0.0;
22951  if (Print_timings_level_load_balance>2)
22952  {
22953  tt_start_nodes_on_non_overlapped_shd_bnd=TimingHelpers::timer();
22954  }
22955 
22956  // Mark the nodes on original boundaries not overlapped by shared
22957  // boundaries
22958  std::map<unsigned, std::map<Node*, bool> >
22959  node_on_bnd_not_overlapped_by_shd_bnd;
22960 
22961  // Loop over the edges of the original boundaries
22962  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
22963  elements_edges_on_boundary.begin();
22964  it_map != elements_edges_on_boundary.end(); it_map++)
22965  {
22966  // Get the edge
22967  std::pair<Node*,Node*> edge_pair = (*it_map).first;
22968  // Is the edge overlaped by a shared boundary
22969  if (!overlapped_edge[edge_pair])
22970  {
22971  // Mark the nodes of the edge as being on an edge not overlaped
22972  // by a shared boundary on the boundary the edge is
22973  unsigned b = (*it_map).second;
22974 
22975  // Get the left node
22976  Node* left_node_pt = edge_pair.first;
22977  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
22978 
22979  // Get the right node
22980  Node* right_node_pt = edge_pair.second;
22981  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
22982 
22983  } // if (!overlapped_edge[edge_pair])
22984 
22985  } // Loop over edges to mark those nodes on overlaped edge by
22986  // shared boundaries
22987 
22988  // The time to compute nodes on non overlapped shared boundaries
22989  if (Print_timings_level_load_balance>2)
22990  {
22991  oomph_info << "CPU for computing nodes on non overlapped shared boundaries (load balance) [9.4]: "
22992  <<TimingHelpers::timer()-tt_start_nodes_on_non_overlapped_shd_bnd
22993  << std::endl;
22994  }
22995 
22996  // ================================================================
22997  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22998  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22999  // ================================================================
23000 
23001  // ==================================================================
23002  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23003  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23004  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23005  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23006  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23007  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23008  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23009  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23010  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23011  // ==================================================================
23012 
23013  // Get the time to sort shared boundaries face elements to create a
23014  // continuous representation of the boundary
23015  double tt_start_join_shd_bnd_face_ele=0.0;
23016  if (Print_timings_level_load_balance>2)
23017  {
23018  tt_start_join_shd_bnd_face_ele=TimingHelpers::timer();
23019  }
23020 
23021  // Face elements that create the shared boundaries (sorted)
23022  Vector<Vector<Vector<FiniteElement*> > > sorted_face_ele_pt(nproc);
23023 
23024  // Bulk elements that create the shared boundaries (sorted)
23025  Vector<Vector<Vector<FiniteElement*> > > sorted_ele_pt(nproc);
23026 
23027  // Face indexes of the bulk elements that create the shared
23028  // boundaries (sorted)
23029  Vector<Vector<Vector<int> > > sorted_face_index_ele(nproc);
23030 
23031  // Store the edge boundary id associated with a shared boundary (if
23032  // any, this apply for shared boundaries lying on internal
23033  // boundaries, then the shared boundary is marked as overlaping an
23034  // internal boundary)
23035  Vector<Vector<int> > edge_boundary_id(nproc);
23036 
23037  // Store the connection information obtained when joining the face
23038  // elements (used for connection purposes only)
23039  Vector<Vector<Vector<int> > > sorted_connection_info(nproc);
23040 
23041  // Store the local shared boundary id associated to the elements
23042  // that will give rise to the shared boundaries (used to compute the
23043  // global shared boundary id from the local shared boundary id)
23044  Vector<Vector<unsigned> > proc_local_shared_boundary_id(nproc);
23045 
23046  // Map that associates the local shared boundary id with the list of
23047  // nodes that create it
23048  std::map<unsigned, std::list<Node*> >
23049  local_shd_bnd_id_to_sorted_list_node_pt;
23050 
23051  // Local shared bouonday id (used to locally identify the lists of
23052  // nodes that create shared boundaries, it is also useful to
23053  // identify connections with shared boundaries)
23054  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23055 
23056  // Sort the face elements, using the nodes at its ends
23057 
23058  // Mark the done elements
23059  std::map<FiniteElement*, bool> done_ele;
23060 
23061  // Mark the inverted elements
23062  std::map<FiniteElement*, bool> is_inverted;
23063 
23064  // Sort the face elements to get the number of shared boundaries
23065  // with in each processor
23066  for (unsigned iproc = 0; iproc < nproc; iproc++)
23067  {
23068  // No face elements with myself
23069  if (iproc != my_rank)
23070  {
23071  // Get the number of unsorted face elements with the iproc
23072  // processor
23073  const unsigned nunsorted_face_ele =
23074  unsorted_face_ele_pt[iproc].size();
23075  // Count the number of sorted face elements
23076  unsigned nsorted_face_ele = 0;
23077 
23078  // Iterate until all the face elements have been sorted
23079  while (nsorted_face_ele < nunsorted_face_ele)
23080  {
23081  // Take the first nonsorted element an use it as root element,
23082  // add elements to the left and right until no more elements
23083  // left or until a stop condition is reached (connection,
23084  // boundary node)
23085 
23086 #ifdef PARANOID
23087  // Flag to indicate if a root element was found
23088  bool found_root_element = false;
23089 #endif
23090 
23091  // Index of the found root element
23092  unsigned root_index = 0;
23093 
23094  // List that contains the sorted face elements
23095  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23096 
23097  // List that contains the sorted elements
23098  std::list<FiniteElement*> tmp_sorted_ele_pt;
23099 
23100  // List that contains the sorted face indexes of the bulk
23101  // elements
23102  std::list<int> tmp_sorted_face_index_ele;
23103 
23104  // Storing for the sorting nodes extracted from the face
23105  // elements. The sorted nodes are used to identify connections
23106  // among new shared boundaries or original boundaries
23107  std::list<Node*> tmp_sorted_nodes_pt;
23108  // Clear the storage (just in case)
23109  tmp_sorted_nodes_pt.clear();
23110 
23111  // The initial and final nodes
23112  Node* initial_node_pt = 0;
23113  Node* final_node_pt = 0;
23114 
23115  // Store the original boundary id related with the root face
23116  // element (if there is one)
23117  int root_edge_bound_id = -1;
23118 
23119  // Loop over the unsorted face elements until a root element
23120  // is found
23121  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23122  {
23123  // Get a root element
23124  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23125  // Is the element already done?
23126  if (!done_ele[root_ele_pt])
23127  {
23128  // Get the edge boundary id associated with the edge (if
23129  // there is one)
23130  root_edge_bound_id = edge_boundary[iproc][e];
23131  // Add the face element to the list of sorted face
23132  // elements
23133  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23134  // Add the bulk element to the list of sorted elements
23135  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23136  // Add the face index to the list of sorted face index
23137  // elements
23138  tmp_sorted_face_index_ele.push_back(
23139  unsorted_face_index_ele[iproc][e]);
23140 
23141  // Get the nodes and state them as initial and final
23142  const unsigned nnodes = root_ele_pt->nnode();
23143  // Check if the face element should be treated as inverted
23144  if (!treat_as_inverted[iproc][e])
23145  {
23146  initial_node_pt = root_ele_pt->node_pt(0);
23147  final_node_pt = root_ele_pt->node_pt(nnodes-1);
23148  }
23149  else
23150  {
23151  initial_node_pt = root_ele_pt->node_pt(nnodes-1);
23152  final_node_pt = root_ele_pt->node_pt(0);
23153  }
23154  // Add both nodes to the list of sorted nodes
23155  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23156  tmp_sorted_nodes_pt.push_back(final_node_pt);
23157 
23158  // Mark the element as done
23159  done_ele[root_ele_pt] = true;
23160  // Check if the face element should be treated as inverted
23161  if (!treat_as_inverted[iproc][e])
23162  {
23163  // Mark the element as not inverted
23164  is_inverted[root_ele_pt] = false;
23165  }
23166  else
23167  {
23168  // Mark the element as inverted
23169  is_inverted[root_ele_pt] = true;
23170  }
23171  // Increase the counter for sorted face elements
23172  nsorted_face_ele++;
23173  // Set the root index
23174  root_index = e;
23175 #ifdef PARANOID
23176  // Set the flag of found root element
23177  found_root_element = true;
23178 #endif
23179  // Break the loop
23180  break;
23181 
23182  } // if (!done_ele[root_ele_pt])
23183 
23184  } // for (e < nunsorted_face_ele)
23185 
23186 #ifdef PARANOID
23187  if (!found_root_element)
23188  {
23189  std::ostringstream error_stream;
23190  error_stream
23191  << "It was not possible the found the root element\n\n";
23192  throw OomphLibError(error_stream.str(),
23193  OOMPH_CURRENT_FUNCTION,
23194  OOMPH_EXCEPTION_LOCATION);
23195  }
23196 #endif
23197 
23198  // New element added. Continue adding elements -- or nodes --
23199  // to the list of shared boundary elements while a new element
23200  // has been added to the list (we have just added the root
23201  // element)
23202  bool new_element_added = true;
23203 
23204  // Similarly that in the
23205  // "create_polylines_from_halo_elements_helper() method, we
23206  // extract the nodes (in order) that will create the shared
23207  // polyline, and also check for connections with the just
23208  // added face elements (nodes)
23209 
23210  // Flags to indicate at which end (of the sorted list of
23211  // boundary elements) the element was added (left or right)
23212  bool element_added_to_the_left = false;
23213  bool element_added_to_the_right = false;
23214 
23215  // Flag to indicate that the "left" node of the element added
23216  // to the left was found to be shared with another boundary
23217  bool connection_to_the_left = false;
23218 
23219  // Flag to indicate that the "right" node of the element added
23220  // to the right was found to be shared with another boundary
23221  bool connection_to_the_right = false;
23222 
23223  // Flag to stop the adding of elements (and nodes) to the
23224  // current shared boundary (because there are connections at
23225  // both ends)
23226  bool current_polyline_has_connections_at_both_ends = false;
23227 
23228  // Store the boundary ids of the polylines to connect (only
23229  // used when the polyline was found to have a connection)
23230  // -1: Indicates no connection
23231  // -2: Indicates connection with itself
23232  // -3: Indicates no connection BUT STOP adding elements
23233  // -because the node is a boundary node whose boundary is no
23234  // -currently part of the domain. Think in one of the corner
23235  // -nodes of a triangle touchin a boundary that does no longer
23236  // -exist
23237  // Any other value: Boundary id to connect
23238  int bound_id_connection_to_the_left = -1;
23239  int bound_id_connection_to_the_right = -1;
23240 
23241  // Get the global degree of the node (notice the local degree
23242  // has been updated to global degree)
23243  const unsigned initial_node_degree =
23244  global_node_degree[initial_node_pt];
23245 
23246  // Flag to indicate we are calling the method from a load
23247  // balance sub-rutine
23248  const bool called_for_load_balance=true;
23249 
23250  // Check if the nodes of the root element have connections
23251  // ... to the left
23252  bound_id_connection_to_the_left =
23253  this->check_connections_of_polyline_nodes(
23254  element_in_processor_pt,
23255  root_edge_bound_id,
23256  overlapped_edge,
23257  node_on_bnd_not_overlapped_by_shd_bnd,
23258  tmp_sorted_nodes_pt,
23259  local_shd_bnd_id_to_sorted_list_node_pt,
23260  initial_node_degree,
23261  initial_node_pt,
23262  called_for_load_balance);
23263 
23264  // If there is a stop condition then set the corresponding
23265  // flag
23266  if (bound_id_connection_to_the_left != -1)
23267  {
23268  connection_to_the_left = true;
23269  } // if (bound_id_connection_to_the_left != -1)
23270 
23271  // Get the global degree of the node (notice the local degree
23272  // has been updated to global degree)
23273  const unsigned final_node_degree =
23274  global_node_degree[final_node_pt];
23275 
23276  // ... and to the right
23277  bound_id_connection_to_the_right =
23278  this->check_connections_of_polyline_nodes(
23279  element_in_processor_pt,
23280  root_edge_bound_id,
23281  overlapped_edge,
23282  node_on_bnd_not_overlapped_by_shd_bnd,
23283  tmp_sorted_nodes_pt,
23284  local_shd_bnd_id_to_sorted_list_node_pt,
23285  final_node_degree,
23286  final_node_pt,
23287  called_for_load_balance);
23288 
23289  // If there is a stop condition then set the corresponding
23290  // flag
23291  if (bound_id_connection_to_the_right != -1)
23292  {
23293  connection_to_the_right = true;
23294  } // if (bound_id_connection_to_the_right != -1)
23295 
23296  // If the current shared boundary has connections at both ends
23297  // then stop the adding of elements (and nodes)
23298  if (connection_to_the_left && connection_to_the_right)
23299  {current_polyline_has_connections_at_both_ends = true;}
23300 
23301  // Continue searching for more elements to add if
23302  // 1) A new element was added at the left or right of the list
23303  // 2) There are more possible elements to add
23304  // 3) The nodes at the edges of the added element (left or
23305  // right) are not part of any other previous shared
23306  // boundary
23307  while(new_element_added &&
23308  (nsorted_face_ele < nunsorted_face_ele)
23309  && !current_polyline_has_connections_at_both_ends)
23310  {
23311  // Loop over the remaining elements and try to create a
23312  // contiguous set of face elements, start looking from the
23313  // root index. Any previous element should have been already
23314  // visited
23315  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23316  {
23317  // Reset the flags for added elements, to the left and right
23318  new_element_added = false;
23319  element_added_to_the_left = false;
23320  element_added_to_the_right = false;
23321 
23322  // Get the "e"-th element on the vector
23323  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23324  // Get the boundary id associated with the edge (if any)
23325  const int edge_bound_id = edge_boundary[iproc][e];
23326  // Check if the element has been already sorted and the
23327  // related edge bound id is the same as the root edge (if
23328  // any)
23329  if (!done_ele[tmp_ele_pt]
23330  && (edge_bound_id == root_edge_bound_id))
23331  {
23332  // Get the number of nodes on the current element
23333  const unsigned nnodes = tmp_ele_pt->nnode();
23334  // Get the first and last node of the element
23335  // Check if the face element should be treated as inverted
23336  Node* first_node_pt = 0;
23337  Node* last_node_pt = 0;
23338  if (!treat_as_inverted[iproc][e])
23339  {
23340  first_node_pt = tmp_ele_pt->node_pt(0);
23341  last_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23342  }
23343  else
23344  {
23345  first_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23346  last_node_pt = tmp_ele_pt->node_pt(0);
23347  }
23348 
23349  // A pointer to the node at the left or right of the
23350  // just added element, the most left or the most right
23351  // node
23352  Node* new_added_node_pt = 0;
23353 
23354  // Check if the element goes to the left
23355  if (initial_node_pt == last_node_pt &&
23356  !connection_to_the_left)
23357  {
23358  // Update the initial node and the just added node
23359  new_added_node_pt = initial_node_pt = first_node_pt;
23360  // Add the most left node
23361  tmp_sorted_nodes_pt.push_front(first_node_pt);
23362  // Add the face element to the list of sorted face
23363  // elements
23364  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23365  // Add the bulk element to the list of sorted elements
23366  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23367  // Add the face index to the list of sorted face index
23368  // elements
23369  tmp_sorted_face_index_ele.push_front(
23370  unsorted_face_index_ele[iproc][e]);
23371  if (!treat_as_inverted[iproc][e])
23372  {
23373  // Mark the element as not inverted
23374  is_inverted[tmp_ele_pt] = false;
23375  }
23376  else
23377  {
23378  // Mark the element as inverted
23379  is_inverted[tmp_ele_pt] = true;
23380  }
23381  // Set the flag to indicate a new element was added
23382  new_element_added = true;
23383  // Set the flag to indicate the element was added to
23384  // the left
23385  element_added_to_the_left = true;
23386  }
23387  // Check if the element goes to the left (but inverted)
23388  else if (initial_node_pt == first_node_pt &&
23389  !connection_to_the_left)
23390  {
23391  // Update the initial node and the just added node
23392  new_added_node_pt = initial_node_pt = last_node_pt;
23393  // Add the most left node
23394  tmp_sorted_nodes_pt.push_front(last_node_pt);
23395  // Add the face element to the list of sorted face
23396  // elements
23397  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23398  // Add the bulk element to the list of sorted elements
23399  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23400  // Add the face index to the list of sorted face index
23401  // elements
23402  tmp_sorted_face_index_ele.push_front(
23403  unsorted_face_index_ele[iproc][e]);
23404  if (!treat_as_inverted[iproc][e])
23405  {
23406  // Mark the element as inverted
23407  is_inverted[tmp_ele_pt] = true;
23408  }
23409  else
23410  {
23411  // Mark the element as not inverted
23412  is_inverted[tmp_ele_pt] = false;
23413  }
23414  // Set the flag to indicate a new element was added
23415  new_element_added = true;
23416  // Set the flag to indicate the element was added to
23417  // the left
23418  element_added_to_the_left = true;
23419  }
23420  // Check if the elements goes to the right
23421  else if (final_node_pt == first_node_pt
23422  && !connection_to_the_right)
23423  {
23424  // Update the final node and the just added node
23425  new_added_node_pt = final_node_pt = last_node_pt;
23426  // Add the most right node
23427  tmp_sorted_nodes_pt.push_back(last_node_pt);
23428  // Add the face element to the list of sorted face
23429  // elements
23430  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23431  // Add the bulk element to the list of sorted elements
23432  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23433  // Add the face index to the list of sorted face index
23434  // elements
23435  tmp_sorted_face_index_ele.push_back(
23436  unsorted_face_index_ele[iproc][e]);
23437  if (!treat_as_inverted[iproc][e])
23438  {
23439  // Mark the element as not inverted
23440  is_inverted[tmp_ele_pt] = false;
23441  }
23442  else
23443  {
23444  // Mark the element as inverted
23445  is_inverted[tmp_ele_pt] = true;
23446  }
23447  // Set the flag to indicate a new element was added
23448  new_element_added = true;
23449  // Set the flag to indicate the element was added to
23450  // the right
23451  element_added_to_the_right = true;
23452  }
23453  // Check if the elements goes to the right (but inverted)
23454  else if (final_node_pt == last_node_pt &&
23455  !connection_to_the_right)
23456  {
23457  // Update the final node and the just added node
23458  new_added_node_pt = final_node_pt = first_node_pt;
23459  // Add the most right node
23460  tmp_sorted_nodes_pt.push_back(first_node_pt);
23461  // Add the face element to the list of sorted face
23462  // elements
23463  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23464  // Add the bulk element to the list of sorted elements
23465  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23466  // Add the face index to the list of sorted face index
23467  // elements
23468  tmp_sorted_face_index_ele.push_back(
23469  unsorted_face_index_ele[iproc][e]);
23470  if (!treat_as_inverted[iproc][e])
23471  {
23472  // Mark the element as inverted
23473  is_inverted[tmp_ele_pt] = true;
23474  }
23475  else
23476  {
23477  // Mark the element as not inverted
23478  is_inverted[tmp_ele_pt] = false;
23479  }
23480  // Set the flag to indicate a new elements was added
23481  new_element_added = true;
23482  // Set the flag to indicate the element was added to
23483  // the right
23484  element_added_to_the_right = true;
23485  }
23486 
23487  // Do additional stuff if the element was added
23488  if (new_element_added)
23489  {
23490  // Mark the element as done
23491  done_ele[tmp_ele_pt] = true;
23492  // Increase the counter for sorted face elements
23493  nsorted_face_ele++;
23494 
23495  // Get the global degree of the node (notice the
23496  // local degree has been updated to global degree)
23497  const unsigned new_added_node_degree =
23498  global_node_degree[new_added_node_pt];
23499 
23500  // Based on which side the element was added, look for
23501  // connections on that side
23502 
23503  // Verify for connections to the left (we need to
23504  // check for the connection variable too, since
23505  // after a connection has been done we no longer
23506  // need to verify for this condition)
23507  if (element_added_to_the_left && !connection_to_the_left)
23508  {
23509  // Check for connection
23510  bound_id_connection_to_the_left =
23511  this->check_connections_of_polyline_nodes(
23512  element_in_processor_pt,
23513  root_edge_bound_id,
23514  overlapped_edge,
23515  node_on_bnd_not_overlapped_by_shd_bnd,
23516  tmp_sorted_nodes_pt,
23517  local_shd_bnd_id_to_sorted_list_node_pt,
23518  new_added_node_degree,
23519  new_added_node_pt,
23520  called_for_load_balance);
23521 
23522  // If there is a stop condition then set the
23523  // corresponding flag
23524  if (bound_id_connection_to_the_left != -1)
23525  {
23526  connection_to_the_left = true;
23527  } // if (bound_id_connection_to_the_left != -1)
23528 
23529  } // if (node_added_to_the_left &&
23530  // !connection_to_the_left)
23531 
23532  // Verify for connections to the right (we need to
23533  // check for the connection variable too, since
23534  // after a connection has been done we no longer
23535  // need to verify for this condition)
23536  if (element_added_to_the_right && !connection_to_the_right)
23537  {
23538  // Check for connection
23539  bound_id_connection_to_the_right =
23540  this->check_connections_of_polyline_nodes(
23541  element_in_processor_pt,
23542  root_edge_bound_id,
23543  overlapped_edge,
23544  node_on_bnd_not_overlapped_by_shd_bnd,
23545  tmp_sorted_nodes_pt,
23546  local_shd_bnd_id_to_sorted_list_node_pt,
23547  new_added_node_degree,
23548  new_added_node_pt,
23549  called_for_load_balance);
23550 
23551  // If there is a stop condition then set the
23552  // corresponding flag
23553  if (bound_id_connection_to_the_right != -1)
23554  {
23555  connection_to_the_right = true;
23556  } // if (bound_id_connection_to_the_right != -1)
23557 
23558  } // if (node_added_to_the_right &&
23559  // !connection_to_the_right)
23560 
23561  // If the current shared boundary has connections at
23562  // both ends then stop the adding of elements (and
23563  // nodes)
23564  if (connection_to_the_left && connection_to_the_right)
23565  {current_polyline_has_connections_at_both_ends = true;}
23566 
23567  // Break the for (looping over unsorted face
23568  // elements) and re-start looking for more elements
23569  // that fit to the left or right
23570  break;
23571 
23572  } // if (new_element_added)
23573 
23574  } // if (!done_ele[tmp_ele_pt])
23575 
23576  } // for (e < nunsorted_face_ele)
23577 
23578  } // while(new_element_added &&
23579  // (nsorted_face_ele < nunsorted_face_ele)
23580  // && !current_polyline_has_connections_at_both_ends)
23581 
23582  // ------------------------------------------------------------
23583  // Before assigning a local shared boundary id to the list of
23584  // nodes and boundary elements, check for any loop that the
23585  // shared boundary may be creating
23586 
23587  // The vector of the elements
23588  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23589  // Store the list of elements on a vector of elements
23590  for (std::list<FiniteElement*>::iterator it =
23591  tmp_sorted_ele_pt.begin(); it != tmp_sorted_ele_pt.end(); it++)
23592  {
23593  tmp_vector_sorted_ele_pt.push_back((*it));
23594  }
23595 
23596  // The vector of the face elements
23597  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23598  // Store the list of face elements on a vector of face
23599  // elements
23600  for (std::list<FiniteElement*>::iterator it =
23601  tmp_sorted_face_ele_pt.begin();
23602  it != tmp_sorted_face_ele_pt.end(); it++)
23603  {
23604  tmp_vector_sorted_face_ele_pt.push_back((*it));
23605  }
23606 
23607  // The vector of the face indexes
23608  Vector<int> tmp_vector_sorted_face_index_ele;
23609  // Store the list of elements on a vector of elements
23610  for (std::list<int>::iterator it =
23611  tmp_sorted_face_index_ele.begin();
23612  it != tmp_sorted_face_index_ele.end(); it++)
23613  {
23614  tmp_vector_sorted_face_index_ele.push_back((*it));
23615  }
23616 
23617  // Store the nodes for the new shared polylines without loops
23618  Vector<std::list<Node*> > final_sorted_nodes_pt;
23619  // Store the boundary elements of the shared polyline without
23620  // loops
23621  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
23622  // Store the boundary face elements of the shared polyline
23623  // without loops
23624  Vector<Vector<FiniteElement*> > final_boundary_face_element_pt;
23625  // Face indexes of the boundary elements without loops
23626  Vector<Vector<int> > final_face_index_element;
23627  // Connection flags (to the left) of the shared boundaries
23628  // without loops
23629  Vector<int> final_bound_id_connection_to_the_left;
23630  // Connection flags (to the right) of the shared boundaries
23631  // without loops
23632  Vector<int> final_bound_id_connection_to_the_right;
23633 
23634  // Break any possible loop created by the shared polyline
23635  this->break_loops_on_shared_polyline_load_balance_helper(
23636  local_shd_bnd_id,
23637  tmp_sorted_nodes_pt,
23638  tmp_vector_sorted_ele_pt,
23639  tmp_vector_sorted_face_ele_pt, tmp_vector_sorted_face_index_ele,
23640  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
23641  final_sorted_nodes_pt,
23642  final_boundary_element_pt,
23643  final_boundary_face_element_pt, final_face_index_element,
23644  final_bound_id_connection_to_the_left,
23645  final_bound_id_connection_to_the_right);
23646 
23647  // Get the number of final sorted nodes
23648  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23649 
23650  // Loop over the list of final sorted nodes
23651  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23652  {
23653  // Store the list of nodes that gave rise to the shared
23654  // boundary
23655  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23656  final_sorted_nodes_pt[i];
23657 
23658  // Store the local shared boundary id assigned to the
23659  // elements that will create the shared boundary
23660  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23661 
23662  // Increase the shared boundary id (note that this is only
23663  // used to keep track of the list of nodes that create the
23664  // shared boundaries in the current processor)
23665  local_shd_bnd_id++;
23666 
23667  // Include the vector of elements to the sorted vector
23668  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23669 
23670  // Include the vector of face elements to the sorted vector
23671  sorted_face_ele_pt[iproc].
23672  push_back(final_boundary_face_element_pt[i]);
23673 
23674  // Include the vector of elements to the sorted vector
23675  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23676 
23677  // Include the possible associated boundary id to the vector
23678  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23679 
23680  // Include the connection information associated with the
23681  // current set of face elements (that will give rise to a
23682  // shared polyline
23683  // The temporal storage for the boundary connections ids
23684  Vector<int> bnd_connections_ids(2);
23685  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23686  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23687  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23688 
23689  } // for (i < n_final_sorted_nodes)
23690 
23691  } // while (nsorted_face_ele < nunsorted_face_ele)
23692 
23693  } // if (iproc != my_rank)
23694 
23695  } // for (iproc < nproc)
23696 
23697  // The time to sort shared boundaries face elements to create a
23698  // continuous representation of the boundary
23699  if (Print_timings_level_load_balance>2)
23700  {
23701  oomph_info << "CPU for joining shared boundary face elements (load balance) [9.5]: "
23702  <<TimingHelpers::timer()-tt_start_join_shd_bnd_face_ele
23703  << std::endl;
23704  }
23705 
23706  // ==================================================================
23707  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23708  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23709  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23710  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23711  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23712  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23713  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23714  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23715  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23716  // ==================================================================
23717 
23718  // ==================================================================
23719  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23720  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23721  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23722  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23723  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23724  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23725  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23726  // ALSO COMPUTED
23727  // ==================================================================
23728 
23729  // Get the time to compute new shared boundaries ids
23730  double tt_start_get_new_shared_boundaries_ids=0.0;
23731  if (Print_timings_level_load_balance>2)
23732  {
23733  tt_start_get_new_shared_boundaries_ids=TimingHelpers::timer();
23734  }
23735 
23736  // Get the number of shared boundaries with in each processor
23737  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23738  // Loop over the processors
23739  for (unsigned iproc = 0; iproc < nproc; iproc++)
23740  {
23741  // No shared boundaries with myself
23742  if (iproc != my_rank)
23743  {
23744  // Store the number of shared boundaries of the current
23745  // processor (my_rank) with the iproc processor
23746  nshared_boundaries_with_processor[iproc] =
23747  sorted_face_ele_pt[iproc].size();
23748 
23749  } // if (iproc != my_rank)
23750 
23751  } // for (iproc < nproc)
23752 
23753  // Each processor sends the number of shared boundaries that it has
23754  // with in each other processor to the "root_processor" which will
23755  // be in charge of checking and computing the global shared
23756  // boundaries ids
23757  const unsigned root_processor = 0;
23758 
23759  // Get the communicator of the mesh
23760  OomphCommunicator* comm_pt = this->communicator_pt();
23761 
23762  // Container where to store the info. received from other processor
23763  // in root. It receives from all processors the number of shared
23764  // boundaries that each one has with any other processor
23765  Vector<unsigned> flat_unsigned_root_received_data(nproc*nproc);
23766 
23767  // Gather the info. in the "root_processor"
23768  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
23769  // each processor
23770  nproc, // Total number of data to send from each
23771  // processor
23772  MPI_UNSIGNED,
23773  &flat_unsigned_root_received_data[0], // Container where
23774  // to receive the
23775  // info. from all
23776  // the processors
23777  nproc, // Number of data to receive from each processor
23778  MPI_UNSIGNED,
23779  root_processor, // The processor that receives all the
23780  // info.
23781  comm_pt->mpi_comm());
23782 
23783  // Container where root store the info. that will be sent back to
23784  // all processor, because root performs a Broadcast operation then
23785  // the info. is received in the same container
23786  Vector<unsigned> flat_unsigned_root_send_receive_data;
23787 
23788  // Compute the new initial and final shared boundary id (they are
23789  // based on the global number of shared boundaries)
23790  unsigned new_initial_shared_boundary_id = 0;
23791  unsigned new_final_shared_boundary_id = 0;
23792 
23793  // Compute the boundaries ids for the shared boundaries
23794  if (my_rank == root_processor)
23795  {
23796  // Change the representation of the data received from all
23797  // processors to a matrix representation for ease access
23798  Vector<Vector<unsigned> > root_nshared_bound_proc_with_proc(nproc);
23799  // Loop over the processors and get the number of shared
23800  // boundaries of processor iproc with jproc
23801  for (unsigned iproc = 0; iproc < nproc; iproc++)
23802  {
23803  // Resize the vector to store the data
23804  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
23805  // Loop over the processors and get the number of shared
23806  // boundaries of processor iproc with jproc
23807  for (unsigned jproc = 0; jproc < nproc; jproc++)
23808  {
23809  root_nshared_bound_proc_with_proc[iproc][jproc] =
23810  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
23811 
23812  } // for (jproc < nproc)
23813 
23814  } // for (iproc < nproc)
23815 
23816 #ifdef PARANOID
23817  // Check that the same number of boundaries are shared by two
23818  // specific processors
23819  for (unsigned iproc = 0; iproc < nproc; iproc++)
23820  {
23821  for (unsigned jproc = 0; jproc < iproc; jproc++)
23822  {
23823  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
23824  root_nshared_bound_proc_with_proc[jproc][iproc])
23825  {
23826  std::ostringstream error_stream;
23827  error_stream
23828  << "ROOT PROCESSOR ERROR\n\n"
23829  << "The number of shared boundaries between processor ("
23830  << iproc << ") and (" << jproc << ") is not the same:\n"
23831  << "Shared boundaries of processor (" << iproc
23832  << ") with processor (" << jproc << "): ("
23833  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
23834  << "Shared boundaries of processor (" << jproc
23835  << ") with processor (" << iproc << "): ("
23836  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
23837  throw OomphLibError(error_stream.str(),
23838  OOMPH_CURRENT_FUNCTION,
23839  OOMPH_EXCEPTION_LOCATION);
23840 
23841  } // The number of shared boundaries between processors
23842  // "iproc" and "jproc" is not the same
23843 
23844  } // for (jproc < iproc)
23845 
23846  } // for (iproc < nproc)
23847 #endif
23848 
23849  // The enumeration of the shared boundaries starts from the lowest
23850  // processor number to the highest processor number
23851 
23852  // Two processors share the same boundaries ids, the lowest
23853  // processor number is the one in charge of computing the shared
23854  // boundaries ids
23855  Vector<Vector<unsigned> > start_shared_bound_id_proc_with_proc(nproc);
23856  // Resize the vector, we can not do it when storing the
23857  // info. because of the strategy to save the info.
23858  for (unsigned iproc = 0; iproc < nproc; iproc++)
23859  {start_shared_bound_id_proc_with_proc[iproc].resize(nproc);}
23860 
23861  // The shared boundaries ids start from the current number of
23862  // original boundaries
23863  unsigned shared_bound_id = this->nboundary();
23864 
23865  // Set the new initial shared boundary id
23866  new_initial_shared_boundary_id = shared_bound_id;
23867 
23868  // Assign the global shared boundary id for the shared boundaries
23869  for (unsigned iproc = 0; iproc < nproc; iproc++)
23870  {
23871  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
23872  {
23873  // Are there shared boundaries between the pair of processors
23874  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23875  {
23876  // Set the start boundary id of processor "iproc" with
23877  // processor "jproc" and viceversa
23878  start_shared_bound_id_proc_with_proc[iproc][jproc] = shared_bound_id;
23879  start_shared_bound_id_proc_with_proc[jproc][iproc] = shared_bound_id;
23880  // Increase the shared boundary id counter with as many
23881  // shared boundaries there are between the iproc and jproc
23882  // processor
23883  shared_bound_id+= root_nshared_bound_proc_with_proc[iproc][jproc];
23884  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23885 
23886  } // for (jproc < iproc)
23887 
23888  } // for (iproc < nproc)
23889 
23890  // Set the new final shared boundary id
23891  new_final_shared_boundary_id = shared_bound_id;
23892 
23893  // Prepare the info. to send back to each processor
23894  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc*nproc);
23895 
23896  // Copy the info. to the storage to send the info. back to other
23897  // processors
23898  for (unsigned iproc = 0; iproc < nproc; iproc++)
23899  {
23900  for (unsigned jproc = 0; jproc < nproc; jproc++)
23901  {
23902  // Get the initial shared boundary id between each pair of
23903  // processors (iproc, jproc)
23904  const unsigned initial_shd_bnd_id =
23905  start_shared_bound_id_proc_with_proc[iproc][jproc];
23906  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
23907 
23908  // .. then copy the number of shared boundaries that there are
23909  // between processor iproc and jproc
23910  const unsigned nshared_bnd_iproc_jproc =
23911  root_nshared_bound_proc_with_proc[iproc][jproc];
23912  flat_unsigned_root_send_receive_data.push_back(nshared_bnd_iproc_jproc);
23913 
23914  } // for (jproc < nproc)
23915 
23916  } // for (iproc < nproc)
23917 
23918  // .. at the end of the data to send include the global initial
23919  // shared boundary id
23920  flat_unsigned_root_send_receive_data.
23921  push_back(new_initial_shared_boundary_id);
23922 
23923  // ... and the global final shared boundary id
23924  flat_unsigned_root_send_receive_data.
23925  push_back(new_final_shared_boundary_id);
23926 
23927  } // if (my_rank == root_processor)
23928 
23929  // Send the initial shared boundaries ids and the number of shared
23930  // boundaries between all procesors to all processors. All
23931  // processors need to know this info.
23932 
23933  // The number of data that will be sent by root to other processors
23934  // and the number of data that other processors receive from root,
23935  // it is the same because it is performed via a Broadcast
23936  unsigned root_ndata_sent_to_all_proc =
23937  flat_unsigned_root_send_receive_data.size();
23938 
23939  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
23940  1, MPI_UNSIGNED, root_processor,
23941  comm_pt->mpi_comm());
23942 
23943  // Resize the container if this is a processor that receives data
23944  if (my_rank != root_processor)
23945  {
23946  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
23947  }
23948 
23949  // Send back the start boundaries ids for the shared boundaries
23950  // Scatter the info. from the "root_processor"
23951  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
23952  // each
23953  // processor
23954  root_ndata_sent_to_all_proc, // Total number of data to
23955  // send to each processor
23956  MPI_UNSIGNED,
23957  root_processor, // The processor that sends all the info.
23958  comm_pt->mpi_comm());
23959 
23960  // The container to store the initial shared boundaries ids between
23961  // each pair of processors
23962  Vector<Vector<unsigned> > initial_shared_bound_id_proc_with_proc(nproc);
23963 
23964  // All processors need to know how many shared boundaries there are
23965  // between each pair of processors
23966 
23967  // The number of shared boundaries between each pair of processors
23968  Vector<Vector<unsigned> > nshared_bound_proc_with_proc(nproc);
23969 
23970  unsigned iflat_counter = 0;
23971  // Fill the containers with the received info. from root processor
23972  for (unsigned iproc = 0; iproc < nproc; iproc++)
23973  {
23974  // Resize the containers
23975  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
23976  nshared_bound_proc_with_proc[iproc].resize(nproc);
23977 
23978  // Loop over the processors
23979  for (unsigned jproc = 0; jproc < nproc; jproc++)
23980  {
23981  // Get the initial shared boundary id between each pair of
23982  // processors (iproc, jproc)
23983  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
23984  flat_unsigned_root_send_receive_data[iflat_counter++];
23985 
23986  // .. and copy the number of shared boundaries that there are
23987  // between processor iproc and jproc
23988  nshared_bound_proc_with_proc[iproc][jproc] =
23989  flat_unsigned_root_send_receive_data[iflat_counter++];
23990 
23991  } // for (jproc < nproc)
23992 
23993  } // for (iproc < nproc)
23994 
23995  // Read the new initial shared boundary id
23996  new_initial_shared_boundary_id =
23997  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-2];
23998 
23999  // Read the new final shared boundary id
24000  new_final_shared_boundary_id =
24001  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-1];
24002 
24003  // The time to compute new shared boundaries ids
24004  if (Print_timings_level_load_balance>2)
24005  {
24006  oomph_info << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24007  <<TimingHelpers::timer()-tt_start_get_new_shared_boundaries_ids
24008  << std::endl;
24009  }
24010 
24011  // ==================================================================
24012  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24013  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24014  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24015  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24016  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24017  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24018  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24019  // ==================================================================
24020 
24021  // ==================================================================
24022  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24023  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24024  // SHARED BOUNDARIES INFO.
24025  // ==================================================================
24026 
24027  // Get the time to create new shared boundaries representations
24028  double tt_start_create_new_shared_boundaries_polylines=0.0;
24029  if (Print_timings_level_load_balance>2)
24030  {
24031  tt_start_create_new_shared_boundaries_polylines=TimingHelpers::timer();
24032  }
24033 
24034  // Create the shared boundaries and establish all the related info.
24035  // - Create Polylines
24036  // - Store shared boundary elements
24037  // - Fill data structures to know which shared boundaries belong to
24038  // which processor
24039 
24040  // Resize the shared polylines container
24041  this->flush_shared_boundary_polyline_pt();
24042  this->Shared_boundary_polyline_pt.resize(nproc);
24043 
24044  // Resize for the boundaries ids shared with all processors
24045  this->Shared_boundaries_ids.clear();
24046  this->Shared_boundaries_ids.resize(nproc);
24047  for (unsigned iproc = 0; iproc < nproc; iproc++)
24048  {
24049  this->Shared_boundaries_ids[iproc].clear();
24050  this->Shared_boundaries_ids[iproc].resize(nproc);
24051  } // for (iproc < nproc)
24052 
24053  // Clear data
24054  this->Shared_boundary_from_processors.clear();
24055  this->Shared_boundary_overlaps_internal_boundary.clear();
24056  this->Boundary_was_splitted.clear();
24057  this->Boundary_subpolylines.clear();
24058  this->Boundary_marked_as_shared_boundary.clear();
24059 
24060  // Flush data
24061  this->flush_shared_boundary_element();
24062  this->flush_face_index_at_shared_boundary();
24063  this->flush_shared_boundary_node();
24064  this->flush_sorted_shared_boundary_node();
24065 
24066  // Store the old local inital shared boundary id (used to map from
24067  // local shared boundary id to global shared boundary id)
24068  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24069 
24070  // Update the initial and final shared boundary id
24071  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24072  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24073 
24074  // Storage for the new created polylines between the current
24075  // processor (my_rank) and the other processors, unsorted polylines
24076  Vector<TriangleMeshPolyLine *> unsorted_polylines_pt;
24077 
24078  // Map to get the global shared boundary id from the local shared
24079  // boundary id. Note that this is only used to get the global shared
24080  // boundary id when the shared boundary that is being created has
24081  // connections
24082  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24083 
24084  // Each processor knows the boundaries ids for each of the shared
24085  // boundaries it has, establish that info. in the proper containers
24086  // Additionally, store the shared boundaries of ALL processors with
24087  // ALL processors, but only create the shared boundaries (and their
24088  // respective polylines) of the current processor (my_rank)
24089  for (unsigned iproc = 0; iproc < nproc; iproc++)
24090  {
24091  // Avoid creating double shared boundaries, the shared boundaries
24092  // created between processor "iproc" and processor "jproc" are the
24093  // same than those created between processor "jproc" and processor
24094  // "iproc"
24095  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24096  {
24097  // If we are working with the current processor (my_rank) then
24098  // create the shared boundaries, if that is not the case then
24099  // only fill the info. on the proper containers
24100  if (iproc == my_rank || jproc == my_rank)
24101  {
24102  // Check the condition that made it get here
24103  unsigned ref_proc = 0;
24104  if (iproc == my_rank)
24105  {ref_proc = jproc;}
24106  else if (jproc == my_rank)
24107  {ref_proc = iproc;}
24108 
24109  // Get the number of shared boundaries between processor iproc
24110  // and processor jproc
24111  const unsigned nshared_bound_iproc_jproc =
24112  nshared_bound_proc_with_proc[iproc][jproc];
24113 
24114  // Loop over the number of shared boundaries
24115  for (unsigned counter = 0;
24116  counter < nshared_bound_iproc_jproc;
24117  counter++)
24118  {
24119  // Compute the shared boundary id for the shared boundary
24120  const unsigned shd_bnd_id =
24121  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24122  // Set up the shared boundaries between "iproc" (my_rank)
24123  // and "jproc"
24124  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24125  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24126 
24127  // Specify the processors involved for the creation of the
24128  // shared boundary
24129  Vector<unsigned> processors(2);
24130  processors[0] = iproc;
24131  processors[1] = jproc;
24132  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24133 
24134  // Get the possible root edge id associated to the shared
24135  // boundary (useful when the shared boundary overlaps an
24136  // original boundary)
24137  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24138  // Check if the shared boundary is overlapping (or is part)
24139  // of an internal boundary
24140  if (root_edge_bound_id != -1)
24141  {
24142  // If the shared boundary is part of an internal boundary then
24143  // mark the shared boundary
24144  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24145  static_cast<unsigned>(root_edge_bound_id);
24146  } // if (root_edge_bound_id != -1)
24147 
24148  // Storing for the nodes of the polyline (these are different
24149  // from the nodes on the face elements -- it is actually a
24150  // sub-set -- since the polyline is created from the first and
24151  // last nodes on the face elements)
24152  Vector<Node*> node_pt_to_create_shared_polyline;
24153 
24154  // Add the first node for the very first face element. In
24155  // the loop we will only add the last node of the face
24156  // element
24157  FiniteElement* first_face_ele_pt =
24158  sorted_face_ele_pt[ref_proc][counter][0];
24159 
24160  // Get the number of nodes on the first face element
24161  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24162  if (!is_inverted[first_face_ele_pt])
24163  {
24164  // Get the first node
24165  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24166  // Add the node to create the polyline
24167  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24168  // Add the first node to the shared boundary
24169  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24170  }
24171  else
24172  {
24173  // Get the first node in the inverted face element
24174  Node* first_node_pt =
24175  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24176  // Add the node to create the polyline
24177  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24178  // Add the first node to the shared boundary
24179  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24180  }
24181 
24182  // ... and extract only the last nodes of the face elements
24183  // in the next loop and add them in the vector of nodes to
24184  // create polylines (node_pt_to_create_shared_polyline)
24185 
24186  // Get the number of elements
24187  const unsigned nshared_boundary_elements =
24188  sorted_face_ele_pt[ref_proc][counter].size();
24189 
24190  // Store the shared boundary elements, nodes and get the
24191  // sorted nodes to create the polyline
24192  for (unsigned ie = 0 ; ie < nshared_boundary_elements; ie++)
24193  {
24194  // Get the bulk element version of the face element
24195  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24196 
24197  // Add the shared boundary element and associate it to the
24198  // "shd_bnd_id"
24199  this->add_shared_boundary_element(shd_bnd_id,
24200  bulk_ele_pt);
24201 
24202  // Get the face index from which the face element was
24203  // created from the bulk element
24204  const int face_index =
24205  sorted_face_index_ele[ref_proc][counter][ie];
24206 
24207  // Add the face index to the face indexes of the shared
24208  // boundary
24209  this->add_face_index_at_shared_boundary(shd_bnd_id,
24210  face_index);
24211 
24212  // Get the face element to obtain the last node
24213  FiniteElement* face_ele_pt =
24214  sorted_face_ele_pt[ref_proc][counter][ie];
24215 
24216  // Get the number of nodes
24217  const unsigned nnodes = face_ele_pt->nnode();
24218  if (!is_inverted[face_ele_pt])
24219  {
24220  // We have already added the first node, then start from
24221  // the second one
24222  for (unsigned n = 1; n < nnodes; n++)
24223  {
24224  // Get the node to be added
24225  Node* node_pt = face_ele_pt->node_pt(n);
24226  // Add the node and associate it to the shared boundary
24227  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24228  } // for (n < nnodes)
24229 
24230  // Add the last node of the face element to the vector of
24231  // nodes to create the polyline
24232  // Get the last node
24233  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24234  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24235  } // if (!is_inverted[face_ele_pt])
24236  else
24237  {
24238  // We have already added the first node, then start from
24239  // the second one (in reverse order)
24240  for (int n = nnodes-2; n >= 0; n--)
24241  {
24242  // Get the node to be added
24243  Node* node_pt = face_ele_pt->node_pt(n);
24244  // Add the node and associate it to the shared boundary
24245  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24246  } // for (n < nnodes)
24247 
24248  // Add the last node of the face element to the vector of
24249  // nodes to create the polyline
24250  // Get the last node
24251  Node* last_node_pt = face_ele_pt->node_pt(0);
24252  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24253 
24254  } // else if (!is_inverted[face_ele_pt])
24255 
24256  } // for (ie < nshared_boundary_elements)
24257 
24258  // The number of nodes for the shared boundary polyline
24259  const unsigned nnodes_to_create_shared_boundary =
24260  node_pt_to_create_shared_polyline.size();
24261 
24262  // Get the vertices that create the shared boundary polyline
24263  Vector<Vector<double> > vertices(nnodes_to_create_shared_boundary);
24264  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24265  {
24266  vertices[n].resize(2);
24267  // Get the node
24268  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24269  // Get the vertices
24270  vertices[n][0] = tmp_node_pt->x(0);
24271  vertices[n][1] = tmp_node_pt->x(1);
24272  } // for (n < nnodes_to_create_shared_boundary)
24273 
24274  // Create the polyline
24275  TriangleMeshPolyLine *polyline_pt =
24276  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24277 
24278  // Updates bnd_id<--->curve section map
24279  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24280 
24281  // Add the new created polyline to the list of unsorted
24282  // polylines
24283  unsorted_polylines_pt.push_back(polyline_pt);
24284 
24285  // Mark the polyline for deletion (when calling destructor)
24286  this->Free_curve_section_pt.insert(polyline_pt);
24287 
24288  // Now assign the connection information
24289  // ---------------------------------------------------------
24290  // Get the local shared boundary id associated to the
24291  // elements that gave rise to this shared boundary
24292  const unsigned local_shd_bnd_id =
24293  proc_local_shared_boundary_id[ref_proc][counter];
24294 
24295  // Associate the local shared boundary to the global shared
24296  // boundary
24297  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24298 
24299  // Get the correct shared boundaries ids, from the local
24300  // shared boundaries ids established at the identification
24301  // of the conections
24302 
24303  // Get the local bnd id for the connection to the left
24304  int tmp_bnd_id_connection_to_the_left =
24305  sorted_connection_info[ref_proc][counter][0];
24306  // Get the local bnd id for the connection to the right
24307  int tmp_bnd_id_connection_to_the_right =
24308  sorted_connection_info[ref_proc][counter][1];
24309 
24310  // The global shared boundaries ids for connections to the
24311  // left or right
24312  int bnd_id_connection_to_the_left = -1;
24313  int bnd_id_connection_to_the_right = -1;
24314 
24315  // To the left
24316  // --------------
24317 
24318  // If the connection is with the same shared boundary then
24319  // set the current boundary id
24320  if (tmp_bnd_id_connection_to_the_left == -2)
24321  {
24322  // Set the current shared boundary id
24323  bnd_id_connection_to_the_left = shd_bnd_id;
24324  } // if (tmp_bnd_id_connection_to_the_left == -2)
24325 
24326  // Check if the connection was a stop adding nodes condition
24327  if (tmp_bnd_id_connection_to_the_left == -3)
24328  {
24329  // Set as no connected
24330  bnd_id_connection_to_the_left = -1;
24331  } // if (tmp_bnd_id_connection_to_the_left == -3)
24332 
24333  // There is a connection with another boundary, check if it
24334  // is a shared boundary or an original boundary
24335  if (tmp_bnd_id_connection_to_the_left >=
24336  static_cast<int>(old_local_shd_bnd_id))
24337  {
24338  // The connection is with a shared boundary, get the
24339  // global shared boundary id and set the connection
24340 #ifdef PARANOID
24341  std::map<unsigned, unsigned>::iterator it =
24342  local_to_global_shd_bnd_id.find(
24343  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24344  // If the global shared boundary id was not found we
24345  // are in trouble
24346  if (it==local_to_global_shd_bnd_id.end())
24347  {
24348  std::stringstream error_message;
24349  error_message
24350  << "The global shared boundary id was not found for\n"
24351  << "the local shared boundary shared with processor ("
24352  << ref_proc <<").\n"
24353  << "This processor: (" << my_rank << ")\n"
24354  << "Boundary shared with processor: (" << ref_proc << ")\n"
24355  << "Local shared boundary: ("
24356  << tmp_bnd_id_connection_to_the_left << ")\n";
24357  throw OomphLibError(error_message.str(),
24358  OOMPH_CURRENT_FUNCTION,
24359  OOMPH_EXCEPTION_LOCATION);
24360  } // if (it==local_to_global_shd_bnd_id.end())
24361 #endif
24362 
24363  // Get the global shared boundary id
24364  bnd_id_connection_to_the_left =
24365  local_to_global_shd_bnd_id[
24366  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left)];
24367 
24368  }
24369  else
24370  {
24371  // The connection is with an original boundary, copy
24372  // the boundary id
24373  bnd_id_connection_to_the_left =
24374  tmp_bnd_id_connection_to_the_left;
24375 
24376  } // else (connection with a shared boundary)
24377 
24378  // To the right
24379  // --------------
24380 
24381  // If the connection is with the same shared boundary then
24382  // set the current boundary id
24383  if (tmp_bnd_id_connection_to_the_right == -2)
24384  {
24385  // Set the current shared boundary id
24386  bnd_id_connection_to_the_right = shd_bnd_id;
24387  } // if (tmp_bnd_id_connection_to_the_right == -2)
24388 
24389  // Check if the connection was a stop adding nodes condition
24390  if (tmp_bnd_id_connection_to_the_right == -3)
24391  {
24392  // Set as no connected
24393  bnd_id_connection_to_the_right = -1;
24394  } // if (tmp_bnd_id_connection_to_the_right == -3)
24395 
24396  // There is a connection with another boundary, check if it
24397  // is a shared boundary or an original boundary
24398  if (tmp_bnd_id_connection_to_the_right >=
24399  static_cast<int>(old_local_shd_bnd_id))
24400  {
24401  // The connection is with a shared boundary, get the
24402  // global shared boundary id and set the connection
24403 #ifdef PARANOID
24404  std::map<unsigned, unsigned>::iterator it =
24405  local_to_global_shd_bnd_id.find(
24406  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24407  // If the global shared boundary id was not found we
24408  // are in trouble
24409  if (it==local_to_global_shd_bnd_id.end())
24410  {
24411  std::stringstream error_message;
24412  error_message
24413  << "The global shared boundary id was not found for\n"
24414  << "the local shared boundary shared with processor ("
24415  << ref_proc <<").\n"
24416  << "This processor: (" << my_rank << ")\n"
24417  << "Boundary shared with processor: (" << ref_proc << ")\n"
24418  << "Local shared boundary: ("
24419  << tmp_bnd_id_connection_to_the_right << ")\n";
24420  throw OomphLibError(error_message.str(),
24421  OOMPH_CURRENT_FUNCTION,
24422  OOMPH_EXCEPTION_LOCATION);
24423  } // if (it==local_to_global_shd_bnd_id.end())
24424 #endif
24425  // Get the global shared boundary id
24426  bnd_id_connection_to_the_right =
24427  local_to_global_shd_bnd_id[
24428  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right)];
24429 
24430  }
24431  else
24432  {
24433  // The connection is with an original boundary, copy the
24434  // boundary id
24435  bnd_id_connection_to_the_right =
24436  tmp_bnd_id_connection_to_the_right;
24437 
24438  } // else (connection with a shared boundary)
24439 
24440  // --------------------------------
24441  // Set the connection to the left
24442  if (bnd_id_connection_to_the_left != -1)
24443  {
24444  // Get the unsigned version of the boundary id to the left
24445  const unsigned ubnd_id_connection_to_the_left =
24446  static_cast<unsigned>(bnd_id_connection_to_the_left);
24447  // Set the initial vertex as connected
24448  polyline_pt->set_initial_vertex_connected();
24449  // Set the initial vertex connected boundary id
24450  polyline_pt->initial_vertex_connected_bnd_id() =
24451  ubnd_id_connection_to_the_left;
24452  // Set the chunk number to zero
24453  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24454 
24455  } // if (bnd_id_connection_to_the_left != -1)
24456 
24457  // ---------------------------------
24458  // Set the connection to the right
24459  if (bnd_id_connection_to_the_right != -1)
24460  {
24461  // Get the unsigned version of the boundary id to the
24462  // right
24463  const unsigned ubnd_id_connection_to_the_right =
24464  static_cast<unsigned>(bnd_id_connection_to_the_right);
24465  // Set the final vertex as connected
24466  polyline_pt->set_final_vertex_connected();
24467  // Set the final vertex connected boundary id
24468  polyline_pt->final_vertex_connected_bnd_id() =
24469  ubnd_id_connection_to_the_right;
24470  // Set the chunk number to zero
24471  polyline_pt->final_vertex_connected_n_chunk() = 0;
24472 
24473  } // if (bnd_id_connection_to_the_right != -1)
24474 
24475  } // for (counter < nshared_bound_iproc_jproc)
24476 
24477  } // if (iproc == my_rank || jproc == my_rank)
24478  else
24479  {
24480  // We are not working with the current processor, then we only
24481  // need to fill the containers
24482 
24483  // Get the number of shared boundaries between processor iproc
24484  // and processor jproc
24485  const unsigned nshared_bound_iproc_jproc =
24486  nshared_bound_proc_with_proc[iproc][jproc];
24487  // Loop over the number of shared boundaries
24488  for (unsigned counter = 0;
24489  counter < nshared_bound_iproc_jproc;
24490  counter++)
24491  {
24492  // Compute the shared boundary id for the shared boundary
24493  const unsigned shd_bnd_id =
24494  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24495 
24496  // Set up the shared boundaries between "iproc" and "jproc"
24497  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24498  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24499 
24500  // Specify the processors involved for the creation of the
24501  // shared boundary
24502  Vector<unsigned> processors(2);
24503  processors[0] = iproc;
24504  processors[1] = jproc;
24505  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24506 
24507  } // for (counter < nshared_bound_iproc_jproc)
24508 
24509  } // else if (iproc == my_rank || jproc == my_rank)
24510 
24511  } // for (jproc < nproc)
24512 
24513  } // for (iproc < nproc)
24514 
24515  // Get the time to create new shared boundaries representations
24516  if (Print_timings_level_load_balance>2)
24517  {
24518  oomph_info << "CPU for creating new shared boundaries representations (load balance) [9.7]: "
24519  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries_polylines
24520  << std::endl;
24521  }
24522 
24523  // ==================================================================
24524  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24525  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24526  // SHARED BOUNDARIES INFO.
24527  // ==================================================================
24528 
24529  // ==================================================================
24530  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24531  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24532  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24533  // ELEMENTS
24534  // ==================================================================
24535 
24536  // Get the time to create the new shared curves
24537  double tt_start_create_new_shared_curves=0.0;
24538  if (Print_timings_level_load_balance>2)
24539  {
24540  tt_start_create_new_shared_curves=TimingHelpers::timer();
24541  }
24542 
24543  // Sort the polylines and find if they create a contiguous open
24544  // curve
24545  if (unsorted_polylines_pt.size() > 0)
24546  {
24547  // Now that we have all the new unsorted polylines on "my_rank"x
24548  // processor it is time to sort them so they be all contiguous
24549  this->sort_polylines_helper(unsorted_polylines_pt,
24550  this->Shared_boundary_polyline_pt[my_rank]);
24551  }
24552 
24553  // Free the memory allocated for the face elements
24554  for (unsigned iproc = 0; iproc < nproc; iproc++)
24555  {
24556  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24557  for (unsigned e = 0; e < nface_ele; e++)
24558  {
24559  delete unsorted_face_ele_pt[iproc][e];
24560  unsorted_face_ele_pt[iproc][e] = 0;
24561  } // for (e < nface_ele)
24562 
24563  } // for (iproc < nproc)
24564 
24565  // The time to create the new shared curves
24566  if (Print_timings_level_load_balance>2)
24567  {
24568  oomph_info << "CPU for creating the new shared curves (load balance) [9.8]: "
24569  <<TimingHelpers::timer()-tt_start_create_new_shared_curves
24570  << std::endl;
24571  }
24572 
24573  // ==================================================================
24574  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24575  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24576  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24577  // ELEMENTS
24578  // ==================================================================
24579 
24580  }
24581 
24582  //======================================================================
24583  // Computes the degree of the nodes on the shared boundaries, the
24584  // degree of the node is computed from the global graph created by the
24585  // shared boundaries of all processors
24586  //======================================================================
24587  template <class ELEMENT>
24589  compute_shared_node_degree_helper(Vector<Vector<FiniteElement*> >
24590  &unsorted_face_ele_pt,
24591  std::map<Node*, unsigned>
24592  &global_node_degree)
24593  {
24594  // Get the rank and number of processors
24595  const unsigned nproc = this->communicator_pt()->nproc();
24596  const unsigned my_rank = this->communicator_pt()->my_rank();
24597 
24598  // Store a temporary sorting of the nodes, starting from the
24599  // lower-left position
24600  Vector<Vector<Node*> > tmp_sorted_shared_node_pt(nproc);
24601 
24602  // Store the alias of the node, it may be shared by more than two
24603  // processors, they should know that the node is the same
24604  // [0] iproc, processor with which the current processor shared the node
24605  // [1] node #, number of node in the number of nodes shared with iproc
24606  // processor
24607  std::map<Node*, Vector<Vector<unsigned> > > node_alias;
24608 
24609  // Stores the local adjacency matrix
24610  // (nproc*n_shared_nodes*n_shared_nodes)
24611  Vector<Vector<Vector<unsigned> > > local_adjacency_matrix(nproc);
24612 
24613  // Sort the nodes and create the adjacency matrix of each sub-graph
24614  // created by the shared edges
24615  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24616  tmp_sorted_shared_node_pt,
24617  node_alias,
24618  local_adjacency_matrix);
24619 
24620  // Prepare the info. to be sent to the root processor, which will be
24621  // in charge of updating the nodes degree by combining the info. of
24622  // all the processors
24623 
24624  // The flat package with the info. to send to root
24625  Vector<unsigned> package_unsigned_send_data_to_root;
24626 
24627  // Encode the info. that will be sent to the root processor
24628 
24629  // Loop over the temporary sorted nodes between each pair of
24630  // processors
24631  for (unsigned iproc = 0; iproc < nproc; iproc++)
24632  {
24633  // Send the processor index
24634  package_unsigned_send_data_to_root.push_back(iproc);
24635 
24636  // Get the number of nodes shared between the processors
24637  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24638 
24639  // Send the number of nodes shared with the iproc processor
24640  package_unsigned_send_data_to_root.push_back(n_nodes);
24641 
24642  // Loop over the nodes
24643  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24644  {
24645  // Get the node
24646  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24647 
24648  // Get the alias info.
24649  Vector<Vector<unsigned> > alias_node_info = node_alias[shd_node_pt];
24650 
24651  // Get the number of alias for the node
24652  const unsigned n_alias = alias_node_info.size();
24653 
24654  // Send the number of alias assigned to the node
24655  package_unsigned_send_data_to_root.push_back(n_alias);
24656 
24657  // Loop over the alias to include them in the package
24658  for (unsigned i = 0; i < n_alias; i++)
24659  {
24660  // Send the alias info.
24661  // The current processor
24662  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24663  // The prociesso with which is shared
24664  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24665  // The index of the node
24666  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24667  } // for (i < n_alias)
24668 
24669  } // for (ishd < n_nodes)
24670 
24671  // Now send the adjacency matrix
24672  for (unsigned i = 0; i < n_nodes; i++)
24673  {
24674  for (unsigned j = 0; j < n_nodes; j++)
24675  {
24676  // Package the adjacency matrix
24677  package_unsigned_send_data_to_root.
24678  push_back(local_adjacency_matrix[iproc][i][j]);
24679 
24680  } // for (j < n_nodes)
24681 
24682  } // for (i < n_nodes)
24683 
24684  } // for (iproc < nproc)
24685 
24686  // Define the root processor
24687  const unsigned root_processor = 0;
24688 
24689  // Get the communicator of the mesh
24690  OomphCommunicator* comm_pt = this->communicator_pt();
24691 
24692  // Number of data send. from this processor to root processor
24693  unsigned n_unsigned_data_send_to_root =
24694  package_unsigned_send_data_to_root.size();
24695 
24696  // Store the number of data to receive from each processor in root
24697  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24698 
24699  // Send the number of data that each processor will send to root
24700  // Gather the info. in the "root_processor"
24701  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24702  // each processor
24703  1, // Total number of data to send from each processor
24704  MPI_UNSIGNED,
24705  &n_unsigned_data_received_in_root[0], // Container where
24706  // to receive the
24707  // info. from all
24708  // the processors
24709  1, // Number of data to receive from each processor
24710  MPI_UNSIGNED,
24711  root_processor, // The processor that receives all the
24712  // info.
24713  comm_pt->mpi_comm());
24714 
24715  // Compute the total number of data to receive from all processors
24716  unsigned n_unsigned_total_data_receive_in_root = 0;
24717  for (unsigned iproc = 0; iproc < nproc; iproc++)
24718  {
24719  // Add the number of data to receive from each processor
24720  n_unsigned_total_data_receive_in_root+=
24721  n_unsigned_data_received_in_root[iproc];
24722  }
24723 
24724  // Compute the offsets from each processor
24725  Vector<int> root_unsigned_offsets_receive(nproc,0);
24726  root_unsigned_offsets_receive[0] = 0;
24727  for (unsigned iproc = 1; iproc < nproc; iproc++)
24728  {
24729  // Compute the offset to store the values received from each
24730  // processor
24731  root_unsigned_offsets_receive[iproc] =
24732  root_unsigned_offsets_receive[iproc-1] +
24733  n_unsigned_data_received_in_root[iproc-1];
24734  }
24735 
24736  // Create at least one entry so we don't get a seg fault below
24737  if (package_unsigned_send_data_to_root.size()==0)
24738  {
24739  package_unsigned_send_data_to_root.resize(1);
24740  }
24741 
24742  // Vector where to receive the data sent from each processor
24743  Vector<unsigned>
24744  package_unsigned_data_received_root(n_unsigned_total_data_receive_in_root);
24745  if (my_rank!=root_processor)
24746  {
24747  // Create at least one entry so we don't get a seg fault below
24748  if (package_unsigned_data_received_root.size()==0)
24749  {
24750  package_unsigned_data_received_root.resize(1);
24751  }
24752  } // if (my_rank!=root_processor)
24753 
24754  // Gather the info. from all processors
24755  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
24756  // to send
24757  // info. from
24758  // each
24759  // processor
24760  n_unsigned_data_send_to_root, // Total number of data to
24761  // send from each
24762  // processor
24763  MPI_UNSIGNED,
24764  &package_unsigned_data_received_root[0], // Container
24765  // where to
24766  // receive the
24767  // info. from
24768  // all the
24769  // processors
24770  &n_unsigned_data_received_in_root[0], // Number of data
24771  // to receive from
24772  // each processor
24773  &root_unsigned_offsets_receive[0], // The offset to
24774  // store the
24775  // info. from each
24776  // processor
24777  MPI_UNSIGNED,
24778  root_processor, //The processor that receives all the
24779  //info.
24780  comm_pt->mpi_comm());
24781 
24782  // Store the info. to be sent by root to other processors
24783  Vector<unsigned> package_unsigned_data_sent_from_root;
24784  // Total data sent to each processor from root
24785  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
24786 
24787  // The root processor now has all the info. regarding the shared
24788  // nodes and the adjacency matrix of each pair of processors
24789  if (my_rank == root_processor)
24790  {
24791  // Decode the info. received from all processors
24792  // Counter to decode the info.
24793  unsigned decode_counter = 0;
24794 
24795  // Store the local alias of the nodes in each processor
24796  // [x][][][][] iproc
24797  // [][x][][][] jproc
24798  // [][][x][][] inode
24799  // [][][][x][] ialias
24800  // [][][][][x] alias_data
24801  Vector<Vector<Vector<Vector<Vector<unsigned> > > > >
24802  local_node_alias(nproc);
24803  // Store the local adjacency matrix of each processor
24804  Vector<Vector<Vector<Vector<unsigned> > > > local_adjacency_matrix(nproc);
24805 
24806  // Loop over all the processors
24807  for (unsigned iproc = 0; iproc < nproc; iproc++)
24808  {
24809  local_node_alias[iproc].resize(nproc);
24810 
24811  // Resize the local adjacency matrix to store the info. sent
24812  // from all processors
24813  local_adjacency_matrix[iproc].resize(nproc);
24814 
24815  if (n_unsigned_data_received_in_root[iproc] > 0)
24816  {
24817  // Loop over all the processors to decode the info. received
24818  // from each one
24819  for (unsigned jproc = 0; jproc < nproc; jproc++)
24820  {
24821  // Read the processor number to which the info. correspond
24822  const unsigned read_jproc =
24823  package_unsigned_data_received_root[decode_counter++];
24824 
24825  // The read processor must be the same as the jproc, if that
24826  // is not the case then there is a synchronisation issue
24827  if (read_jproc != jproc)
24828  {
24829  std::ostringstream error_stream;
24830  error_stream
24831  << "The read processor is different from the jproc, this is\n"
24832  << "a synchronisation issue. The data are not read in the\n"
24833  << "sameorder as the were packaged\n"
24834  << "Read processor: (" << read_jproc << ")\n"
24835  << "Current jproc: (" << jproc << ")\n\n";
24836  throw OomphLibError(error_stream.str(),
24837  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24838  OOMPH_EXCEPTION_LOCATION);
24839  }
24840 
24841  // Read the number of nodes in the shared boundaries between
24842  // iproc and jproc
24843  const unsigned read_n_shd_nodes_iproc_jproc =
24844  package_unsigned_data_received_root[decode_counter++];
24845 
24846  // Resize the container
24847  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
24848 
24849  // Loop over the number of nodes shared between iproc and
24850  // jproc
24851  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
24852  {
24853  // Read the number of alias of the current ishd node
24854  const unsigned read_n_alias_node_iproc_jproc =
24855  package_unsigned_data_received_root[decode_counter++];
24856 
24857  // Resize the container
24858  local_node_alias[iproc][jproc][ishd].
24859  resize(read_n_alias_node_iproc_jproc);
24860 
24861  for (unsigned ialias = 0;
24862  ialias < read_n_alias_node_iproc_jproc; ialias++)
24863  {
24864  // Resize the container, we know there are three data to
24865  // define the alias of a node
24866  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
24867 
24868  // The 1st processor with which is shared
24869  local_node_alias[iproc][jproc][ishd][ialias][0] =
24870  package_unsigned_data_received_root[decode_counter++];
24871 
24872  // The 2nd processor with which is shared
24873  local_node_alias[iproc][jproc][ishd][ialias][1] =
24874  package_unsigned_data_received_root[decode_counter++];
24875 
24876  // The index of the node in the interaction iproc-jproc
24877  local_node_alias[iproc][jproc][ishd][ialias][2] =
24878  package_unsigned_data_received_root[decode_counter++];
24879 
24880  } // for (ialias < read_n_alias_node_iproc_jproc)
24881 
24882  } // for (ishd < read_n_shd_nodes_iproc_jproc)
24883 
24884  // Resize the local adjacency matrix
24885  local_adjacency_matrix[iproc][jproc].
24886  resize(read_n_shd_nodes_iproc_jproc);
24887  // Read the adjacency matrix sent to root processor
24888  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
24889  {
24890  // Resize the local adjacency matrix
24891  local_adjacency_matrix[iproc][jproc][i].
24892  resize(read_n_shd_nodes_iproc_jproc);
24893  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
24894  {
24895  // Read the adjacency matrix entry
24896  local_adjacency_matrix[iproc][jproc][i][j] =
24897  package_unsigned_data_received_root[decode_counter++];
24898  } // for (j < read_n_shd_nodes_iproc_jproc)
24899 
24900  } // for (i < read_n_shd_nodes_iproc_jproc)
24901 
24902  } // for (jproc < nproc)
24903 
24904  } // for (iproc < nproc)
24905 
24906  } // for (iproc < nproc)
24907 
24908 #ifdef PARANOID
24909  if (decode_counter != n_unsigned_total_data_receive_in_root)
24910  {
24911  std::ostringstream error_stream;
24912  error_stream
24913  << "The number of data decoded in root received from others\n"
24914  << "processors is different from the total number of data received\n"
24915  << "Data decoded: (" << decode_counter << ")\n"
24916  << "Data received: ("<<n_unsigned_total_data_receive_in_root<<")\n\n"
24917  << "This is a synchronisation issue so you are probably sending\n"
24918  << "more or less info. than the one that is being decoded\n\n";
24919  throw OomphLibError(error_stream.str(),
24920  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24921  OOMPH_EXCEPTION_LOCATION);
24922  }
24923 #endif
24924 
24925  // Assign a unique id to the nodes (uses the alias information to
24926  // identify the repetition of a node in other processors). The
24927  // global node id is given by the position (index) in the global
24928  // node alias
24929 
24930  // Keep track of those alias already assigned a unique id
24931  std::map<Vector<unsigned>, bool> alias_done;
24932 
24933  // Store all the alias associated to each node
24934  Vector<Vector<Vector<unsigned> > > global_node_alias;
24935 
24936  // Loop over all the processors
24937  for (unsigned iproc = 0; iproc < nproc; iproc++)
24938  {
24939  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24940  {
24941  // Read the number of nodes shared between the processors
24942  const unsigned n_shd_nodes_iproc_jproc =
24943  local_node_alias[iproc][jproc].size();
24944 #ifdef PARANOID
24945  // Read the number of nodes shared in the other direction
24946  const unsigned n_shd_nodes_jproc_iproc =
24947  local_node_alias[jproc][iproc].size();
24948 
24949  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24950  {
24951  std::ostringstream error_stream;
24952  error_stream
24953  << "The number of nodes shared between iproc and jproc is\n"
24954  << "different from the number of nodes shared between jproc\n"
24955  << "and iproc\n"
24956  << "Nodes shared between processor (" << iproc << ") and "
24957  << "processor ("<<jproc<<"): ("<<n_shd_nodes_iproc_jproc<<")\n"
24958  << "Nodes shared between processor (" << jproc << ") and "
24959  << "processor ("<<iproc<<"): ("<<n_shd_nodes_jproc_iproc<<")\n\n";
24960  throw OomphLibError(error_stream.str(),
24961  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24962  OOMPH_EXCEPTION_LOCATION);
24963  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24964 #endif
24965 
24966  // Loop over the nodes shared between the processors
24967  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
24968  {
24969  // Get the number of alias associated to the node on each
24970  // processor
24971  const unsigned n_alias_iproc_jproc =
24972  local_node_alias[iproc][jproc][ishd].size();
24973  const unsigned n_alias_jproc_iproc =
24974  local_node_alias[jproc][iproc][ishd].size();
24975 
24976  // Store all the found alias to the node
24977  Vector<Vector<unsigned> > node_alias;
24978 
24979  // Flag to indicate if a new alias has been added
24980  bool new_alias_added = false;
24981 
24982  // Start by adding the "direct" alias of the node
24983  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
24984  {
24985  // Get the alias of the node
24986  Vector<unsigned> current_alias =
24987  local_node_alias[iproc][jproc][ishd][ialias];
24988  // Check if already done
24989  if (!alias_done[current_alias])
24990  {
24991  // Add the alias of the node
24992  node_alias.push_back(current_alias);
24993  // Set the flag to indicate a new alias has been added
24994  new_alias_added = true;
24995  // Mark the alias as done
24996  alias_done[current_alias] = true;
24997  } // if (!alias_done[i_alias])
24998 
24999  } // for (ialias < n_alias_iproc_jproc)
25000 
25001  // Start by adding the "direct" alias of the node
25002  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25003  {
25004  // Get the alias of the node
25005  Vector<unsigned> current_alias =
25006  local_node_alias[jproc][iproc][ishd][ialias];
25007 
25008  // Check if already done
25009  if (!alias_done[current_alias])
25010  {
25011  // Add the alias of the node
25012  node_alias.push_back(current_alias);
25013  // Set the flag to indicate a new alias has been added
25014  new_alias_added = true;
25015  // Mark the alias as done
25016  alias_done[current_alias] = true;
25017  } // if (!alias_done[i_alias])
25018 
25019  } // for (ialias < n_alias_jproc_iproc)
25020 
25021  unsigned counter_alias = 0;
25022  // Visit the alias of the node and add any new found
25023  // alias, end until all its alias have been included
25024 
25025  unsigned n_current_alias = node_alias.size();
25026  while(new_alias_added || counter_alias < n_current_alias)
25027  //while(new_alias_added) // we need to check all the alias, including those added during the process
25028  {
25029  new_alias_added = false;
25030  // Store the current visited alias
25031  Vector<unsigned> current_alias = node_alias[counter_alias];
25032 
25033  // Get the alias associated with the current alias
25034  Vector<Vector<unsigned> > alias_of_current_alias =
25035  local_node_alias[current_alias[0]]
25036  [current_alias[1]]
25037  [current_alias[2]];
25038 
25039  // Get all the alias associated with the alias of the
25040  // current alias
25041  const unsigned n_alias = alias_of_current_alias.size();
25042 
25043  // Loop over the new alias and check if require to add
25044  // them
25045  for (unsigned k = 0; k < n_alias; k++)
25046  {
25047  // Get the alias of the node
25048  Vector<unsigned> add_alias =
25049  alias_of_current_alias[k];
25050 
25051  // Check if already done
25052  if (!alias_done[add_alias])
25053  {
25054  // Add the alias of the node
25055  node_alias.push_back(add_alias);
25056  // Set the flag to indicate a new alias has been
25057  // added
25058  new_alias_added = true;
25059  // Mark the alias ad done
25060  alias_done[add_alias] = true;
25061  } // if (!alias_done[i_alias])
25062 
25063  } // for (k < n_alias)
25064 
25065  // Get the alias associated with the current alias (in the
25066  // other direction)
25067  Vector<Vector<unsigned> > alias_of_current_alias2 =
25068  local_node_alias[current_alias[1]]
25069  [current_alias[0]]
25070  [current_alias[2]];
25071 
25072  // Get all the alias associated with the current alias
25073  // (in the other direction)
25074  const unsigned n_alias2 = alias_of_current_alias2.size();
25075 
25076  // Loop over the new alias and check if require to add
25077  // them
25078  for (unsigned k = 0; k < n_alias2; k++)
25079  {
25080  // Get the alias of the node
25081  Vector<unsigned> add_alias =
25082  alias_of_current_alias2[k];
25083 
25084  // Check if already done
25085  if (!alias_done[add_alias])
25086  {
25087  // Add the alias of the node
25088  node_alias.push_back(add_alias);
25089  // Set the flag to indicate a new alias has been
25090  // added
25091  new_alias_added = true;
25092  // Mark the alias ad done
25093  alias_done[add_alias] = true;
25094  } // if (!alias_done[i_alias])
25095 
25096  } // for (k < n_alias)
25097 
25098  // Go for the next alias
25099  counter_alias++;
25100 
25101  // Update the number of alias so that the while stops when
25102  // all the alias have been visited and no new alias was
25103  // added
25104  n_current_alias = node_alias.size();
25105 
25106  } // while(new_alias_added || counter_alias < n_current_alias)
25107 
25108  // If the node has not been previously added, then include
25109  // all its alias
25110  if (node_alias.size() > 0)
25111  {
25112  // Add all the found alias of the node to the global alias
25113  // storage
25114  global_node_alias.push_back(node_alias);
25115  }
25116 
25117  } // for (ishd < n_shd_nodes_iproc_jproc)
25118 
25119  } // for (jproc < nproc)
25120 
25121  } // for (iproc < nproc)
25122 
25123  // We now have the global number of nodes, each with its own id
25124  // (the index in the global_node_alias vector)
25125 
25126  // Get the number of global shared nodes
25127  const unsigned n_global_shared_nodes = global_node_alias.size();
25128 
25129  // Create matrix from local to global shared node id
25130  Vector<Vector<Vector<int> > > local_to_global_shared_node(nproc);
25131 
25132  // Loop over all the processors to resize
25133  for (unsigned iproc = 0; iproc < nproc; iproc++)
25134  {
25135  // Resize the map matrix
25136  local_to_global_shared_node[iproc].resize(nproc);
25137  } // for (iproc < nproc)
25138 
25139  // Loop over all the processors to resize (the third direction,
25140  // required if we want to loop over the half of the matrix only)
25141  for (unsigned iproc = 0; iproc < nproc; iproc++)
25142  {
25143  // Loop over the half of the matrix to resize
25144  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25145  {
25146  // Read the number of nodes shared between the processors
25147  const unsigned n_shd_nodes =
25148  local_node_alias[iproc][jproc].size();
25149 
25150  // Resize the map matrix
25151  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes,-1);
25152 
25153  // ... and resize the other half map matrix
25154  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes,-1);
25155 
25156  } // for (jproc < nproc)
25157 
25158  } // for (iproc < nproc)
25159 
25160  // Fill the matrix for mapping from local to global node id
25161 
25162  // Loop over the global nodes, and for each alias assign the
25163  // corresponding global node id
25164  for (unsigned k = 0 ; k < n_global_shared_nodes; k++)
25165  {
25166  // Get the number of alias associated to the current global node
25167  const unsigned n_alias_global_node = global_node_alias[k].size();
25168  // Loop over the alias and assign the global node id
25169  for (unsigned l = 0; l < n_alias_global_node; l++)
25170  {
25171  // Get the 1st processor
25172  const unsigned iproc = global_node_alias[k][l][0];
25173  // Get the 2nd processor
25174  const unsigned jproc = global_node_alias[k][l][1];
25175  // Get the node number
25176  const unsigned ishd = global_node_alias[k][l][2];
25177  // Assign the global node id
25178  local_to_global_shared_node[iproc][jproc][ishd] = k;
25179 
25180  } // for (l < n_alias_global_node)
25181 
25182  } // for (k < n_global_shared_nodes)
25183 
25184  // Create the global adjacency matrix
25185  Vector<Vector<unsigned> > global_adjacency_matrix(n_global_shared_nodes);
25186  // Resize the global adjacency matrix
25187  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25188  {
25189  // Resize
25190  global_adjacency_matrix[k].resize(n_global_shared_nodes,0);
25191  } // for (k < n_global_shared_nodes)
25192 
25193  // Add the entries to the global adjacency matrix and compute the
25194  // degree of each node
25195 
25196  // Store the degree of the global nodes
25197  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25198 
25199  // Loop over the processors
25200  for (unsigned iproc = 0; iproc < nproc; iproc++)
25201  {
25202  // Loop over the half of the matrix to resize
25203  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25204  {
25205  // Get the number of nodes shared between the processors
25206  const unsigned n_shd_nodes =
25207  local_node_alias[iproc][jproc].size();
25208 
25209  // Search for entries in the local adjacency matrix that set a
25210  // connection among the nodes
25211 
25212  // Loop over the shared nodes in the current pair of
25213  // processors
25214  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25215  {
25216  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25217  {
25218  // Are the nodes associated
25219  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25220  {
25221  // Get the global nodes id
25222 
25223  // Get the "left-node" global id
25224  const int global_shd_node_left =
25225  local_to_global_shared_node[iproc][jproc][ishd];
25226 
25227  // Get the "right-node" global id
25228  const int global_shd_node_right =
25229  local_to_global_shared_node[iproc][jproc][jshd];
25230 
25231 #ifdef PARANOID
25232  // Check if the local nodes have a global node
25233  // associated
25234  if (global_shd_node_left == -1)
25235  {
25236  std::ostringstream error_stream;
25237  error_stream
25238  << "The local node in processors iproc and jproc has no\n"
25239  << "global node assigned\n"
25240  << "iproc processor: (" << iproc << ")\n"
25241  << "jproc processor: ("<<jproc<<")\n"
25242  << "Local node: (" << ishd << ")\n\n";
25243  throw OomphLibError(error_stream.str(),
25244  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25245  OOMPH_EXCEPTION_LOCATION);
25246  }
25247 
25248  // Check if the local nodes have a global node
25249  // associated
25250  if (global_shd_node_right == -1)
25251  {
25252  std::ostringstream error_stream;
25253  error_stream
25254  << "The local node in processors iproc and jproc has no\n"
25255  << "global node assigned\n"
25256  << "iproc processor: (" << iproc << ")\n"
25257  << "jproc processor: ("<<jproc<<")\n"
25258  << "Local node: (" << jshd << ")\n\n";
25259  throw OomphLibError(error_stream.str(),
25260  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25261  OOMPH_EXCEPTION_LOCATION);
25262  }
25263 #endif
25264  // Get the unsigned version of the indexes
25265  const unsigned uleft =
25266  static_cast<unsigned>(global_shd_node_left);
25267  const unsigned uright =
25268  static_cast<unsigned>(global_shd_node_right);
25269 
25270  // Add the entry in the global adjacency matrix
25271  global_adjacency_matrix[uleft][uright]++;
25272 
25273  // ... and in the other direction too
25274  global_adjacency_matrix[uright][uleft]++;
25275 
25276  // Add on to the degree of the left node
25277  global_node_degree[uleft]++;
25278 
25279  // Add on to the degree of the right node
25280  global_node_degree[uright]++;
25281 
25282  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25283 
25284  } // // for (jshd < n_shd_nodes)
25285 
25286  } // for (ishd < n_shd_nodes)
25287 
25288  } // for (jproc < nproc)
25289 
25290  } // for (iproc < nproc)
25291 
25292  // Assign the global degree to the shared nodes between each pair
25293  // of processors
25294  Vector<Vector<Vector<unsigned> > > root_local_node_degree(nproc);
25295  // Resize the container
25296  for (unsigned iproc = 0; iproc < nproc; iproc++)
25297  {
25298  root_local_node_degree[iproc].resize(nproc);
25299  }
25300 
25301  // Loop over the processors and visited their shared nodes
25302  for (unsigned iproc = 0; iproc < nproc; iproc++)
25303  {
25304  // Only visit the half of the data
25305  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25306  {
25307  // Get the number of shared nodes between this pair of
25308  // processors (iproc, jproc)
25309  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25310 
25311  // Resize the container to store the local degree of the nodes
25312  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25313  // ... and in the other way too
25314  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25315 
25316  // Loop over the number of nodes shared between the pair of
25317  // processors
25318  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25319  {
25320  // Get the global node id for the current shared node
25321  const int global_shd_node_id =
25322  local_to_global_shared_node[iproc][jproc][ishd];
25323 
25324 #ifdef PARANOID
25325  // Check if the local nodes have a global node associated
25326  if (global_shd_node_id == -1)
25327  {
25328  std::ostringstream error_stream;
25329  error_stream
25330  << "The local node in processors iproc and jproc has no\n"
25331  << "global node assigned\n"
25332  << "iproc processor: (" << iproc << ")\n"
25333  << "jproc processor: ("<<jproc<<")\n"
25334  << "Local node: (" << ishd << ")\n\n";
25335  throw OomphLibError(error_stream.str(),
25336  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25337  OOMPH_EXCEPTION_LOCATION);
25338  }
25339 #endif
25340 
25341  // Get the unsigned version of the global index
25342  const unsigned uglobal_shd_node_id =
25343  static_cast<unsigned>(global_shd_node_id);
25344 
25345  // Get the degree of the node
25346  const unsigned node_degree =
25347  global_node_degree[uglobal_shd_node_id];
25348 
25349  // Set the degree in the container for the degree of the
25350  // nodes in the local interaction between processors
25351  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25352  // ... and in the other way too
25353  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25354 
25355  } // for (ishd < n_shd_nodes)
25356 
25357  } // for (jproc < nproc)
25358 
25359  } // for (iproc < nproc)
25360 
25361  // Clear the container where the info. will be sent back to each
25362  // processor
25363  package_unsigned_data_sent_from_root.clear();
25364 
25365  // Prepare the data to sent it back to each processor (encode the
25366  // info. to sent to all processors)
25367  for (unsigned iproc = 0; iproc < nproc; iproc++)
25368  {
25369  // Count the number of data sent to iproc processor
25370  unsigned count_n_data_sent_to_iproc = 0;
25371  for (unsigned jproc = 0; jproc < nproc; jproc++)
25372  {
25373  // No shared nodes between the same processor
25374  if (iproc != jproc)
25375  {
25376  // Get the number of nodes shared between the processors
25377  const unsigned n_shd_nodes =
25378  root_local_node_degree[iproc][jproc].size();
25379 
25380  // Add the number of data sent to iproc processor
25381  count_n_data_sent_to_iproc+=n_shd_nodes;
25382 
25383  // Loop over the nodes shared between the pair of processors
25384  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25385  {
25386  package_unsigned_data_sent_from_root.
25387  push_back(root_local_node_degree[iproc][jproc][ishd]);
25388  } // for (ishd < n_shd_nodes)
25389 
25390  } // if (iproc != jproc)
25391 
25392  } // for (jproc < nproc)
25393 
25394  // Set the number of data sent to iproc processor
25395  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25396 
25397  } // for (iproc < nproc)
25398 
25399  } // if (my_rank == root_processor)
25400 
25401  // Total data received from root to this processor
25402  int n_unsigned_data_received_from_root = 0;
25403 
25404  // Get the number of data that each processor receives from root
25405  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25406  // root to each
25407  // processor
25408  1, // The number of data sent from root to each
25409  // processor
25410  MPI_UNSIGNED,
25411  &n_unsigned_data_received_from_root, // Store the
25412  // info. received
25413  // from root
25414  1, // The number of data received from root
25415  MPI_UNSIGNED,
25416  root_processor, // The processor that sends the
25417  // info.
25418  comm_pt->mpi_comm());
25419 
25420  // Receive the info. sent by root
25421  Vector<unsigned>
25422  package_unsigned_data_received_from_root(n_unsigned_data_received_from_root);
25423 
25424  // Compute the offsets to each processor
25425  Vector<int> root_unsigned_offsets_sent(nproc,0);
25426  root_unsigned_offsets_sent[0] = 0;
25427  for (unsigned iproc = 1; iproc < nproc; iproc++)
25428  {
25429  // Compute the offset to send the values to each processor
25430  root_unsigned_offsets_sent[iproc] =
25431  root_unsigned_offsets_sent[iproc-1] +
25432  n_unsigned_data_sent_from_root[iproc-1];
25433  }
25434 
25435  if (my_rank!=root_processor)
25436  {
25437  // Create at least one entry so we don't get a seg fault below
25438  if (package_unsigned_data_sent_from_root.size()==0)
25439  {
25440  package_unsigned_data_sent_from_root.resize(1);
25441  }
25442  } // if (my_rank!=root_processor)
25443 
25444  // Create at least one entry so we don't get a seg fault below
25445  if (package_unsigned_data_received_from_root.size()==0)
25446  {
25447  package_unsigned_data_received_from_root.resize(1);
25448  }
25449 
25450  // Get the data from root
25451  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25452  // info. sent
25453  // from root
25454  // to others
25455  // processors
25456  &n_unsigned_data_sent_from_root[0], // The number of
25457  // data sent from
25458  // root to others
25459  // processors
25460  &root_unsigned_offsets_sent[0], // The offsets to each
25461  // processors
25462  MPI_UNSIGNED,
25463  &package_unsigned_data_received_from_root[0], // The
25464  // storage
25465  // in the
25466  // processor
25467  // that
25468  // receives
25469  // the
25470  // info.
25471  n_unsigned_data_received_from_root, // The number of
25472  // data that the
25473  // current
25474  // processor
25475  // receives from
25476  // root
25477  MPI_UNSIGNED,
25478  root_processor, // The root processors
25479  comm_pt->mpi_comm());
25480 
25481  // Decode the info.
25482 
25483  // Keep track of the already nodes done
25484  std::map<Node*, bool> node_done;
25485 
25486  // Read the global degree assigned to the shared nodes between the
25487  // current processors and the other processors
25488  int decode_counter = 0;
25489  // Store the global degree of the local nodes
25490  Vector<Vector<unsigned> > local_node_degree(nproc);
25491  // Loop over the processors
25492  for (unsigned iproc = 0; iproc < nproc; iproc++)
25493  {
25494  // There are no shared nodes with the current processor itself
25495  if (iproc != my_rank)
25496  {
25497  // Get the number of nodes shared with the iproc processor
25498  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25499 
25500  // Read the global degree of the node
25501  package_unsigned_send_data_to_root.push_back(n_nodes);
25502 
25503  // Loop over the nodes
25504  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25505  {
25506  // Get the node degree assigned to the ishd node in between
25507  // the interaction of the iproc and the current processor
25508  const unsigned node_degree =
25509  package_unsigned_data_received_from_root[decode_counter++];
25510 
25511  // Get the node
25512  Node* shd_node_pt =
25513  tmp_sorted_shared_node_pt[iproc][ishd];
25514 
25515  // Has the node been assigned a global degree
25516  if (!node_done[shd_node_pt])
25517  {
25518  // Assign the global degree to the node
25519  global_node_degree[shd_node_pt] = node_degree;
25520  // Mark the node as done
25521  node_done[shd_node_pt] = true;
25522  }
25523 #ifdef PARANOID
25524  else
25525  {
25526  // The node has been already done, check that the node
25527  // degree is the same as the already assigned
25528  if (global_node_degree[shd_node_pt] != node_degree)
25529  {
25530  std::ostringstream error_stream;
25531  error_stream
25532  << "The local node has already assigned a global degree,\n"
25533  << "however, a different degree for the same node has been\n"
25534  << "read from the data sent from root processor\n"
25535  << "iproc processor: (" << iproc << ")\n"
25536  << "Local node: (" << ishd << ")\n"
25537  << "---------------------------------------------------------\n"
25538  << "Already assigned degree: ("
25539  << global_node_degree[shd_node_pt] << ")\n"
25540  << "New found degree: (" << node_degree << ")\n"
25541  << "---------------------------------------------------------\n"
25542  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25543  << shd_node_pt->x(1) << ")\n\n";
25544  throw OomphLibError(error_stream.str(),
25545  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25546  OOMPH_EXCEPTION_LOCATION);
25547  }
25548 
25549  } // else if (!node_done[shd_node_pt])
25550 #endif // #ifdef PARANOID
25551 
25552  } // for (ishd < n_nodes)
25553 
25554  } // if (iproc != my_rank)
25555 
25556  } // for (iproc < nproc)
25557 
25558 #ifdef PARANOID
25559  // Ensure that all the info. sent from root processor has been read
25560  if (decode_counter != n_unsigned_data_received_from_root)
25561  {
25562  std::ostringstream error_stream;
25563  error_stream
25564  << "The number of data decoded received from root processor is\n"
25565  << "different from the total number of data received from the root\n"
25566  << "processor\n"
25567  << "Data decoded: (" << decode_counter << ")\n"
25568  << "Data received: ("<<n_unsigned_data_received_from_root<<")\n\n"
25569  << "This is a synchronisation issue so you are probably sending\n"
25570  << "more or less info. than the one that is being decoded\n\n";
25571  throw OomphLibError(error_stream.str(),
25572  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25573  OOMPH_EXCEPTION_LOCATION);
25574  }
25575 #endif
25576 
25577  }
25578 
25579  //======================================================================
25580  // Sort the nodes on the new shared boundaries (after load balancing),
25581  // computes the alias of the nodes and creates the adjacency matrix
25582  // that represent the graph created by the shared edges between each
25583  // pair of processors
25584  // ======================================================================
25585  template <class ELEMENT>
25588  Vector<Vector<FiniteElement*> > &unsorted_face_ele_pt,
25589  Vector<Vector<Node*> > &tmp_sorted_shared_node_pt,
25590  std::map<Node*, Vector<Vector<unsigned> > > &node_alias,
25591  Vector<Vector<Vector<unsigned> > > &adjacency_matrix)
25592  {
25593  // Get the number of processors and the rank
25594  const unsigned nproc = this->communicator_pt()->nproc();
25595  const unsigned my_rank = this->communicator_pt()->my_rank();
25596 
25597  // Assign a unique id to each node shared between each pair of
25598  // processors, in this case the current processor and the iproc
25599 
25600  // ... also compute the alias of each node (processor and index of
25601  // the node in all processors where it appears)
25602 
25603  // Clear the alias info
25604  node_alias.clear();
25605 
25606  // Temporary storage for the index of the nodes
25607  Vector<std::map<Node*, unsigned> > tmp_node_index(nproc);
25608 
25609  // Loop over the processors
25610  for (unsigned iproc = 0; iproc < nproc; iproc++)
25611  {
25612  // There is no shared elements between the same processor
25613  if (iproc != my_rank)
25614  {
25615  // Map to mark those nodes already visited
25616  std::map<Node*, bool> done_node;
25617 
25618  // A map is used to sort the nodes using their coordinates as
25619  // the key of the map
25620  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25621  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25622 
25623  // Get the number of unsorted face elements
25624  const unsigned n_unsorted_face_ele =
25625  unsorted_face_ele_pt[iproc].size();
25626 
25627  // Loop over the unsorted elements
25628  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25629  {
25630  // Get a root element
25631  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25632  // Get the left node of the face element
25633  Node* left_node_pt = face_ele_pt->node_pt(0);
25634 
25635  // Check if the node has been already sorted in the
25636  // interaction between the current processor and iproc
25637  // processor
25638  if (!done_node[left_node_pt])
25639  {
25640  std::pair<double, double> vertex =
25641  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25642  sorted_nodes_pt[vertex] = left_node_pt;
25643  // Mark the node as done
25644  done_node[left_node_pt] = true;
25645  }
25646 
25647  // Get the number of nodes of the face element
25648  const unsigned n_nodes = face_ele_pt->nnode();
25649  // Get the right node of the face element
25650  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25651 
25652  // Check if the node has been already sorted in the
25653  // interaction between the current processor and iproc
25654  // processor
25655  if (!done_node[right_node_pt])
25656  {
25657  std::pair<double, double> vertex =
25658  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25659  sorted_nodes_pt[vertex] = right_node_pt;
25660  // Mark the node as done
25661  done_node[right_node_pt] = true;
25662  }
25663 
25664  } // for (e < nunsorted_face_ele)
25665 
25666  // The nodes are already sorted, we need to return them in the
25667  // proper container
25668 
25669  // The counter to enumerate the nodes
25670  unsigned counter = 0;
25671 
25672  // Go through the map container which already have the nodes
25673  // sorted they have the same sorting on all processors
25674  for (std::map<std::pair<double, double>, Node*>::iterator it
25675  = sorted_nodes_pt.begin(); it != sorted_nodes_pt.end(); it++)
25676  {
25677  // Get the node
25678  Node* node_pt = (*it).second;
25679  // Store the node at the corresponding index
25680  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25681 
25682  // Create the temporary access to the node index
25683  tmp_node_index[iproc][node_pt] = counter;
25684 
25685  // Fill the info. for the node alias
25686  Vector<unsigned> alias(3);
25687  // The current processor
25688  alias[0] = my_rank;
25689  // The processor with which is shared
25690  alias[1] = iproc;
25691  // The index with that processor
25692  alias[2] = counter++;
25693 
25694  // Store the info. of the alias
25695  node_alias[node_pt].push_back(alias);
25696 
25697  } // Loop map
25698 
25699  } // if (iproc != my_rank)
25700 
25701  } // for (iproc < nproc)
25702 
25703  // Loop over the processors to resize and initialize the adjacency
25704  // matrix
25705  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25706  {
25707  // Get the number of nodes shared with iproc
25708  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25709  // Resize the adjacency matrix
25710  adjacency_matrix[iproc].resize(n_shd_nodes);
25711  for (unsigned i = 0; i < n_shd_nodes; i++)
25712  {
25713  // Resize the adjacency matrix
25714  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25715 
25716  // Initialize the
25717  for (unsigned j = 0; j < n_shd_nodes; j++)
25718  {
25719  adjacency_matrix[iproc][i][j] = 0;
25720  } // for (j < n_shd_nodes)
25721 
25722  } // for (i < n_shd_nodes)
25723 
25724  } // for (iproc < nproc)
25725 
25726  // Loop over the processors to fill the adjacency matrix
25727  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25728  {
25729  // There is no shared elements between the same processor
25730  if (iproc != my_rank)
25731  {
25732  // Get the number of unsorted face elements
25733  const unsigned n_unsorted_face_ele =
25734  unsorted_face_ele_pt[iproc].size();
25735 
25736  // Loop over the unsorted elements
25737  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25738  {
25739  // Get a root element
25740  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25741  // Get the left node of the face element
25742  Node* left_node_pt = face_ele_pt->node_pt(0);
25743 
25744  // Get the number of nodes of the face element
25745  const unsigned n_nodes = face_ele_pt->nnode();
25746  // Get the right node of the face element
25747  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25748 
25749  // Get the index of each of the nodes
25750  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
25751  const unsigned right_node_index = tmp_node_index[iproc][right_node_pt];
25752 
25753  // Add an entry to the adjacency matrix to indicate the
25754  // association of left and right node
25755  adjacency_matrix[iproc][left_node_index][right_node_index]++;
25756  // ... both directions
25757  adjacency_matrix[iproc][right_node_index][left_node_index]++;
25758 
25759  } // for (e < n_unsorted_face_ele)
25760 
25761  } // if (iproc != my_rank)
25762 
25763  } // for (iproc < nproc)
25764 
25765  }
25766 
25767  //======================================================================
25768  /// \short Get the nodes on the shared boundary (b), these are stored
25769  /// in the segment they belong
25770  //======================================================================
25771  template <class ELEMENT>
25774  const unsigned &shd_bnd_id, Vector<Vector<Node*> > &tmp_segment_nodes)
25775  {
25776  // Clear the data structure were to return the nodes
25777  tmp_segment_nodes.clear();
25778 
25779  // Get the face elements that created the shared boundary from the
25780  // bulk shared boundary elements
25781 
25782 #ifdef PARANOID
25783  // The temporary storage for the halo face elements
25784  Vector<FiniteElement*> halo_shared_face_ele_pt;
25785 #endif
25786  // The temporary storage for the nonhalo face elements
25787  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
25788 
25789  // Get the number of shared boundary elements associated with the
25790  // current shared boundary
25791  const unsigned nshared_bound_ele =
25792  this->nshared_boundary_element(shd_bnd_id);
25793 
25794  // Loop over the elements in the shared boundary to create the face
25795  // elements
25796  for (unsigned e = 0; e < nshared_bound_ele; e++)
25797  {
25798  // Get the shared boundary element
25799  FiniteElement* bulk_ele_pt =
25800  this->shared_boundary_element_pt(shd_bnd_id, e);
25801 
25802  // Get the face index
25803  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
25804 
25805  // Before adding the new element we need to ensure that the edge
25806  // that this element represents has not been already added
25807  FiniteElement* face_ele_pt =
25808  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
25809 
25810  // Nonhalo element
25811  if (!bulk_ele_pt->is_halo())
25812  {
25813  // Add nonhalo shared face element to the container
25814  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
25815  }
25816 #ifdef PARANOID
25817  else // halo element
25818  {
25819  // Add halo shared face element to the container
25820  halo_shared_face_ele_pt.push_back(face_ele_pt);
25821  }
25822 #endif
25823 
25824  } // for (e < nshared_bound_ele)
25825 
25826  // Mark the face elements already used
25827  std::map<FiniteElement*, bool> shared_face_done;
25828 
25829  // Get the number of nonhalo face elements
25830  const unsigned nnonhalo_face_shared_ele =
25831  nonhalo_shared_face_ele_pt.size();
25832 
25833  // If we are in PARANOID mode check that there is one halo element
25834  // for each nonhalo element
25835 #ifdef PARANOID
25836  // Get the number of halo face elements
25837  const unsigned nhalo_face_shared_ele =
25838  halo_shared_face_ele_pt.size();
25839 
25840  // The number of nonhalo shared face boundary elements must be the
25841  // half of the total number of shared boundary elements
25842  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
25843  {
25844  std::ostringstream error_message;
25845  error_message
25846  << "The number of shared boundary elements (" << nshared_bound_ele
25847  << ") is not the double\nof the number of unsorted nonhalo shared "
25848  << "face boundary elements (" << nnonhalo_face_shared_ele
25849  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25850  throw OomphLibError(error_message.str(),
25851  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25852  OOMPH_EXCEPTION_LOCATION);
25853  }
25854 
25855  // The number of halo shared face boundary elements must be the
25856  // half of the total number of shared boundary elements
25857  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
25858  {
25859  std::ostringstream error_message;
25860  error_message
25861  << "The number of shared boundary elements (" << nshared_bound_ele
25862  << ") is not the double\nof the number of unsorted halo shared "
25863  << "face boundary elements (" << nhalo_face_shared_ele
25864  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25865  throw OomphLibError(error_message.str(),
25866  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25867  OOMPH_EXCEPTION_LOCATION);
25868  }
25869 
25870  // ------------------------------------------------------------------
25871  // Loop over the nonhalo face elements and look for the halo face
25872  // element at the other side of the shared boundary
25873  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
25874  {
25875  // Get the inh-th face element
25876  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
25877 
25878  // Get the number of nodes on the face element
25879  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
25880  // Get the first and last node on the element
25881  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
25882  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
25883 
25884  // Now find the (halo) face element at the other side of the
25885  // shared boundary
25886  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
25887  {
25888  // Get the ih-th face element
25889  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
25890 
25891  // Check that the face element has not been done
25892  if (!shared_face_done[halo_face_ele_pt])
25893  {
25894  // Get the number of nodes on the face element
25895  const unsigned nnodes_h = halo_face_ele_pt->nnode();
25896  // Get the first and last node on the element
25897  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
25898  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
25899 
25900  // If the nodes are the same then we have found the (halo)
25901  // face element at the other side of the shared boundary
25902  if (nh_first_node_pt == h_first_node_pt &&
25903  nh_last_node_pt == h_last_node_pt)
25904  {
25905  // Mark the face elements as done
25906  shared_face_done[nonhalo_face_ele_pt] = true;
25907  shared_face_done[halo_face_ele_pt] = true;
25908 
25909  // Break the loop for (ih < nhalo_face_shared_ele)
25910  break;
25911  } // if (nh_first_node_pt == h_first_node_pt &&
25912  // nh_last_node_pt == h_last_node_pt)
25913  else if (nh_first_node_pt == h_last_node_pt &&
25914  nh_last_node_pt == h_first_node_pt)
25915  {
25916  // Mark the face elements as done
25917  shared_face_done[nonhalo_face_ele_pt] = true;
25918  shared_face_done[halo_face_ele_pt] = true;
25919 
25920  // Break the loop for (ih < nhalo_face_shared_ele)
25921  break;
25922  } // else if (nh_first_node_pt == h_last_node_pt &&
25923  // nh_last_node_pt == h_first_node_pt)
25924 
25925  } // if (face_done[halo_face_ele_pt])
25926 
25927  } // for (ih < nhalo_face_shared_ele)
25928 
25929  } // for (inh < nnonhalo_face_shared_ele)
25930 
25931  // The number of done shared face elements MUST be the same as the
25932  // sum of the nonhalo and halo shared boundary face elements
25933  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
25934  shared_face_done.size())
25935  {
25936  std::ostringstream error_message;
25937  error_message
25938  << "The number of DONE shared boundary face elements ("
25939  << shared_face_done.size() << ") is not the same\n as the sum of"
25940  << "the nonhalo face shared boundary elements ("
25941  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
25942  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
25943  << "current boundary (" << shd_bnd_id << ")\n\n";
25944  throw OomphLibError(error_message.str(),
25945  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25946  OOMPH_EXCEPTION_LOCATION);
25947  }
25948 #endif // #ifdef PARANOID
25949 
25950  // -------------------------------------------------------------
25951  // Now sort the face elements
25952  // -------------------------------------------------------------
25953 
25954  // We already have the shared face elements that make the shared
25955  // boundary now sort them to create a contiguous boundary
25956 
25957  // Clear the already done face elements
25958  shared_face_done.clear();
25959 
25960  unsigned nsorted_face_ele = 0;
25961 
25962  // Storing for the sorting nodes extracted from the face elements
25963  std::list<Node*> sorted_nodes;
25964 
25965  // Get the root face element
25966  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
25967  nsorted_face_ele++;
25968 
25969  // Mark face as done
25970  shared_face_done[root_face_ele_pt] = true;
25971 
25972  // The initial and final node on the list
25973  const unsigned nnodes_root = root_face_ele_pt->nnode();
25974  Node *first_node_pt = root_face_ele_pt->node_pt(0);
25975  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
25976 
25977  // Push back on the list the new nodes
25978  sorted_nodes.push_back(first_node_pt);
25979  sorted_nodes.push_back(last_node_pt);
25980 
25981  // Sort the face elements
25982  while (nsorted_face_ele < nnonhalo_face_shared_ele)
25983  {
25984  // Flag to indicate when a node was added
25985  bool node_added = false;
25986 
25987  // Start from the next edge since we have already added the
25988  // previous one as the initial face element
25989  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
25990  {
25991  FiniteElement* tmp_shared_face_ele_pt =
25992  nonhalo_shared_face_ele_pt[iface];
25993 
25994  // If face has not been sorted
25995  if (!shared_face_done[tmp_shared_face_ele_pt])
25996  {
25997  // Get the number of nodes for the current face element
25998  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
25999 
26000  // Get each individual node
26001  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26002  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
26003 
26004  if (left_node_pt == first_node_pt)
26005  {
26006  // Push front the new node
26007  sorted_nodes.push_front(right_node_pt);
26008  first_node_pt = right_node_pt;
26009  node_added = true;
26010  }
26011  else if (left_node_pt == last_node_pt)
26012  {
26013  // Push back the new node
26014  sorted_nodes.push_back(right_node_pt);
26015  last_node_pt = right_node_pt;
26016  node_added = true;
26017  }
26018  else if (right_node_pt == first_node_pt)
26019  {
26020  // Push front the new node
26021  sorted_nodes.push_front(left_node_pt);
26022  first_node_pt = left_node_pt;
26023  node_added = true;
26024  }
26025  else if (right_node_pt == last_node_pt)
26026  {
26027  // Push back the new node
26028  sorted_nodes.push_back(left_node_pt);
26029  last_node_pt = left_node_pt;
26030  node_added = true;
26031  }
26032 
26033  if (node_added)
26034  {
26035  // Mark as done only if one of its nodes has been added to
26036  // the list
26037  shared_face_done[tmp_shared_face_ele_pt] = true;
26038  nsorted_face_ele++;
26039 
26040  // Break the for
26041  break;
26042  }
26043 
26044  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26045 
26046  } // for (iface < nnonhalo_face_shared_ele)
26047 
26048  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26049 
26050  // Here we can safely delete the face elements, they are no longer
26051  // required
26052 
26053  // First the nonhalo face elements
26054  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26055  {
26056  delete nonhalo_shared_face_ele_pt[inh];
26057  nonhalo_shared_face_ele_pt[inh] = 0;
26058  } // for (inh < nnonhalo_face_shared_ele)
26059 
26060 #ifdef PARANOID
26061  // ... then the halo face elements
26062  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26063  {
26064  delete halo_shared_face_ele_pt[ih];
26065  halo_shared_face_ele_pt[ih] = 0;
26066  } // for (inh < nhalo_face_shared_ele)
26067 #endif
26068 
26069  // ------------------------------------------------
26070  // Now copy the nodes to the output container
26071  // ------------------------------------------------
26072  // Get the number of nodes in the container
26073  const unsigned n_nodes = sorted_nodes.size();
26074 
26075  // First resize the container
26076  tmp_segment_nodes.resize(1);
26077  tmp_segment_nodes[0].resize(n_nodes);
26078 
26079  // Counter
26080  unsigned counter = 0;
26081 
26082  // Loop over the list of nodes and copy them in the output container
26083  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26084  it != sorted_nodes.end(); it++)
26085  {
26086  tmp_segment_nodes[0][counter] = (*it);
26087  counter++;
26088  } // Loop over sorted nodes
26089 
26090  }
26091 
26092  //=====start of get_required_elemental_information_load_balance_helper====
26093  /// \short Helper function to get the required elemental information from
26094  /// the element that will be sent to iproc processor.
26095  /// This info. involves the association of the element to a boundary or
26096  /// region.
26097  //========================================================================
26098  template<class ELEMENT>
26101  unsigned& iproc,
26102  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
26103  FiniteElement* ele_pt)
26104  {
26105  // Check if the element is associated with the original boundaries
26106  const unsigned nbound = this->initial_shared_boundary_id();
26107 
26108  // Get the number of processors
26109  const unsigned nproc = this->communicator_pt()->nproc();
26110 
26111  // ------------------------------------------------------------------
26112  // Stores the information regarding the boundaries associated to the
26113  // element (it that is the case)
26114  Vector<unsigned> associated_boundaries;
26115  Vector<unsigned> face_index_on_boundary;
26116 
26117  unsigned counter_face_indexes = 0;
26118 
26119  for (unsigned b = 0; b < nbound; b++)
26120  {
26121  // Get the number of elements associated to boundary i
26122  const unsigned nboundary_ele = nboundary_element(b);
26123  for (unsigned e = 0; e < nboundary_ele; e++)
26124  {
26125  if (ele_pt == this->boundary_element_pt(b,e))
26126  {
26127  // Keep track of the boundaries associated to the element
26128  associated_boundaries.push_back(b);
26129  // Get the face index
26130  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
26131  counter_face_indexes++;
26132 #ifdef PARANOID
26133  if (counter_face_indexes > 2)
26134  {
26135  std::stringstream error_message;
26136  error_message
26137  << "A triangular element can not have more than two of its faces "
26138  << "on a boundary!!!\n\n";
26139  throw OomphLibError(error_message.str(),
26140  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26141  OOMPH_EXCEPTION_LOCATION);
26142  }
26143 #else
26144  // Already found 2 face indexes on the same boundary?
26145  if (counter_face_indexes==2) {break;}
26146 #endif // #ifdef PARANOID
26147 
26148  } // if (ele_pt == this->boundary_element_pt(b,e))
26149 
26150  } // (e < nboundary_ele)
26151 
26152  } // (b < nbound)
26153 
26154  // If the element is associated to any boundary then package all the
26155  // relevant info
26156  const unsigned nassociated_boundaries = associated_boundaries.size();
26157  if (nassociated_boundaries > 0)
26158  {
26159  Flat_packed_unsigneds.push_back(1);
26160 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26161  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
26162 #endif
26163  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26165  std::stringstream junk;
26166  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
26167  Flat_packed_unsigneds_string.push_back(junk.str());
26168 #endif
26169 
26170  // Package the ids of the associated boundaries and the
26171  // corresponding face index for each boundary (if the element is a
26172  // corner element, it will have two faces associated to the
26173  // boundary)
26174  for (unsigned i = 0; i < nassociated_boundaries; i++)
26175  {
26176  unsigned b = associated_boundaries[i];
26177  Flat_packed_unsigneds.push_back(b);
26178 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26179  std::stringstream junk;
26180  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
26181  Flat_packed_unsigneds_string.push_back(junk.str());
26182 #endif
26183  unsigned f = face_index_on_boundary[i];
26184  Flat_packed_unsigneds.push_back(f);
26185 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26186  std::stringstream junk2;
26187  junk2 << "Face index " << f << " for associated boundary " << b;
26188  Flat_packed_unsigneds_string.push_back(junk2.str());
26189 #endif
26190  }
26191 
26192  // If the element is associated to any boundary then we should
26193  // check if the mesh has regions, if that is the case then we need
26194  // to check to which region the boundary element does belong
26195 
26196  // If the mesh has regions we should look for the element
26197  // associated to a boundary and a specified region
26198  Vector<Vector<unsigned> > associated_boundaries_and_regions;
26199  Vector<unsigned> face_index_on_boundary_and_region;
26200 
26201  // Now check for the case when we have regions in the mesh
26202  const unsigned n_regions = this->nregion();
26203  if (n_regions > 1)
26204  {
26205  // Used to count the number of faces associated with
26206  // boundary-regions
26207  unsigned counter_face_indexes_in_regions = 0;
26208  // Loop over the boundaries
26209  for (unsigned b = 0; b < nbound; b++)
26210  {
26211  // Go through each region by getting the region id
26212  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
26213  {
26214  // Get thre region id associated with the (i_reg)-th region
26215  const unsigned region_id =
26216  static_cast<unsigned>(this->Region_attribute[i_reg]);
26217 
26218  // Loop over all elements associated with the current boundary
26219  // and the i_reg-th region and check if the element is part of
26220  // any region
26221  const unsigned nele_in_region =
26222  this->nboundary_element_in_region(b, region_id);
26223  for (unsigned ee = 0; ee < nele_in_region; ee++)
26224  {
26225  // Check if the boundary-region element is the same as the
26226  // element
26227  if (ele_pt ==
26228  this->boundary_element_in_region_pt(b, region_id, ee))
26229  {
26230  // Storage for the boundary and region associated to the
26231  // element
26232  Vector<unsigned> bound_and_region(2);
26233 
26234  // Keep track of the boundaries associated to the element
26235  bound_and_region[0] = b;
26236  // Keep track of the regions associated to the element
26237  bound_and_region[1] = region_id;
26238  // Add the boundaries and regions in the storage to be
26239  // sent to other processors
26240  associated_boundaries_and_regions.push_back(bound_and_region);
26241  // Get the face index and keep track of it
26242  face_index_on_boundary_and_region.push_back(
26243  this->face_index_at_boundary_in_region(b,region_id,ee));
26244 
26245  // Increase the number of faces of the element associated
26246  // to boundary-regions
26247  counter_face_indexes_in_regions++;
26248 
26249 #ifdef PARANOID
26250  if (counter_face_indexes_in_regions > 2)
26251  {
26252  std::stringstream error_message;
26253  error_message
26254  << "A triangular element can not have more than two of its\n"
26255  << "faces on a boundary!!!\n\n";
26256  throw OomphLibError(error_message.str(),
26257  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26258  OOMPH_EXCEPTION_LOCATION);
26259  } // if (counter_face_indexes_in_regions > 2)
26260 #endif
26261 
26262  } // The element is a boundary-region element
26263 
26264  } // for (ee < nele_in_region)
26265 
26266  } // for (i_reg < n_regions)
26267 
26268  } // for (b < nbound)
26269 
26270  } // if (n_regions > 1)
26271 
26272  // Now package the info. to be sent to other processors
26273  const unsigned nassociated_boundaries_and_regions =
26274  associated_boundaries_and_regions.size();
26275  if (nassociated_boundaries_and_regions > 0)
26276  {
26277  Flat_packed_unsigneds.push_back(1);
26278 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26279  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
26280 #endif
26281 
26282  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26283 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26284  std::stringstream junk;
26285  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
26286  Flat_packed_unsigneds_string.push_back(junk.str());
26287 #endif
26288 
26289  // Package the ids of the associated boundaries, regions and the
26290  // corresponding face index for each boundary-region (if the
26291  // element is a corner element, it will have two faces
26292  // associated to the boundary-region)
26293  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26294  {
26295  const unsigned b = associated_boundaries_and_regions[i][0];
26296  Flat_packed_unsigneds.push_back(b);
26297 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26298  std::stringstream junk;
26299  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26300  Flat_packed_unsigneds_string.push_back(junk.str());
26301 #endif
26302 
26303  const unsigned r = associated_boundaries_and_regions[i][1];
26304  Flat_packed_unsigneds.push_back(r);
26305 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26306  std::stringstream junk2;
26307  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26308  Flat_packed_unsigneds_string.push_back(junk2.str());
26309 #endif
26310 
26311  const unsigned f = face_index_on_boundary_and_region[i];
26312  Flat_packed_unsigneds.push_back(f);
26313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26314  std::stringstream junk3;
26315  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
26316  Flat_packed_unsigneds_string.push_back(junk3.str());
26317 #endif
26318  } // for (i < nassociated_boundaries_and_regions)
26319  } // if (nassociated_boundaries_and_regions > 0)
26320  else
26321  {
26322  Flat_packed_unsigneds.push_back(0);
26323 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26324  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
26325 #endif
26326  } // else if (nassociated_boundaries_and_regions > 0)
26327 
26328  }
26329  else
26330  {
26331  Flat_packed_unsigneds.push_back(0);
26332 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26333  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
26334 #endif
26335  }
26336 
26337  // ------------------------------------------------------------
26338  // Now review if the element is associated to a shared boundary
26339 
26340  // Store the shared boundaries, and therefore the face indexes
26341  // associated to the element
26342  Vector<unsigned> associated_shared_boundaries;
26343  Vector<unsigned> face_index_on_shared_boundary;
26344 
26345  // Get the shared boundaries in this processor
26346  Vector<unsigned> my_rank_shared_boundaries_ids;
26347  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26348 
26349  // Get the number of shared boundaries
26350  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26351  // Loop over the shared boundaries
26352  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26353  {
26354  // Get the boundary id
26355  const unsigned sb = my_rank_shared_boundaries_ids[i];
26356 
26357  // Get the number of elements associated to shared boundary sb
26358  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26359  for (unsigned e = 0; e < nboundary_ele; e++)
26360  {
26361  if (ele_pt == this->shared_boundary_element_pt(sb,e))
26362  {
26363  // Keep track of the boundaries associated to the element
26364  associated_shared_boundaries.push_back(sb);
26365  // Get the face index
26366  face_index_on_shared_boundary.push_back(
26367  this->face_index_at_shared_boundary(sb, e));
26368  }
26369  } // (e < nboundary_ele)
26370  } // (i < nmy_rank_shd_bnd)
26371 
26372  // If the element is associated to a shared boundary then package
26373  // all the relevant info
26374  const unsigned nassociated_shared_boundaries =
26375  associated_shared_boundaries.size();
26376  if (nassociated_shared_boundaries > 0)
26377  {
26378  Flat_packed_unsigneds.push_back(3);
26379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26380  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
26381 #endif
26382  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26384  std::stringstream junk;
26385  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
26386  Flat_packed_unsigneds_string.push_back(junk.str());
26387 #endif
26388 
26389  // Package the ids of the associated boundaries
26390  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26391  {
26392  const unsigned b = associated_shared_boundaries[i];
26393  Flat_packed_unsigneds.push_back(b);
26394 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26395  std::stringstream junk;
26396  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
26397  Flat_packed_unsigneds_string.push_back(junk.str());
26398 #endif
26399 
26400  const unsigned f = face_index_on_shared_boundary[i];
26401  Flat_packed_unsigneds.push_back(f);
26402 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26403  std::stringstream junk2;
26404  junk2 << "Face index " << f << " for associated shared boundary " << b;
26405  Flat_packed_unsigneds_string.push_back(junk2.str());
26406 #endif
26407  }
26408  }
26409  else
26410  {
26411  Flat_packed_unsigneds.push_back(0);
26412 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26413  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
26414 #endif
26415  }
26416 
26417  // Now check if the element is haloed with any processor
26418 
26419  // Store the index of the haloed element with the jproc
26420  Vector<Vector<unsigned> > index_haloed(nproc);
26421 
26422  // Loop over the processors
26423  for (unsigned jproc = 0; jproc < nproc; jproc++)
26424  {
26425  // Get the number of haloed elements with jproc
26426  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26427  // Loop over the haloed elements with jproc
26428  for (unsigned ihd =0; ihd < n_haloed_jproc; ihd++)
26429  {
26430  // Is a haloed element?
26431  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26432  {
26433  // Store the haloed index with the jproc processor
26434  index_haloed[jproc].push_back(ihd);
26435  // Break the searching with the jproc processor
26436  break;
26437  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26438 
26439  } // for (ihd < n_haloed_jproc)
26440 
26441  } // for (jproc < nproc)
26442 
26443  // Send the haloed info.
26444  // Loop over the processors
26445  for (unsigned jproc = 0; jproc < nproc; jproc++)
26446  {
26447  // Is the element haloed with the jproc processor
26448  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26449  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26450 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26451  Flat_packed_unsigneds_string.push_back("The number of haloed indexes the element is with processor jproc");
26452 #endif
26453  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26454  {
26455  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26456 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26457  Flat_packed_unsigneds_string.push_back("The haloed index of the element with jproc");
26458 #endif
26459  } // for (ihd < n_index_haloed_jproc)
26460 
26461  } // for (jproc < nproc)
26462 
26463  }
26464 
26465  //======================================================================
26466  /// \short Helper function to add nodes on a new domain as a result of
26467  /// load balance
26468  //======================================================================
26469  template <class ELEMENT>
26472  Vector<Vector<FiniteElement*> >&f_halo_ele_pt,
26473  Vector<Node*> &new_nodes_on_domain,
26474  Node* nod_pt)
26475  {
26476  // Attempt to add this node to the new domain
26477  const unsigned nnew_nodes_on_domain= new_nodes_on_domain.size();
26478  const unsigned new_added_node_index =
26479  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26480 
26481  // If it was added then the new index should match the size of the storage
26482  if (new_added_node_index == nnew_nodes_on_domain)
26483  {
26484  Flat_packed_unsigneds.push_back(1);
26485 
26486 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26487  std::stringstream junk;
26488  junk << "Node needs to be constructed [size="
26489  << Flat_packed_unsigneds.size() << "]; last entry: "
26490  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
26491  Flat_packed_unsigneds_string.push_back(junk.str());
26492 #endif
26493 
26494  // This helper function gets all the required information for the
26495  // specified node and stores it into MPI-sendable information
26496  // so that a new copy can be made on the receiving process
26497  get_required_nodal_information_load_balance_helper(f_halo_ele_pt,
26498  iproc,
26499  nod_pt);
26500  }
26501  else // It was already added
26502  {
26503  Flat_packed_unsigneds.push_back(0);
26504 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26505  std::stringstream junk;
26506  junk << "Node was already added [size="
26507  << Flat_packed_unsigneds.size() << "]; last entry: "
26508  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
26509 
26510  Flat_packed_unsigneds_string.push_back(junk.str());
26511 #endif
26512 
26513  // This node has been already added, so tell the other process
26514  // its index in the equivalent storage
26515  Flat_packed_unsigneds.push_back(new_added_node_index);
26516 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26517  Flat_packed_unsigneds_string.push_back("new added node index");
26518 #endif
26519  }
26520 
26521  }
26522 
26523  //======start of get_required_nodal_information_load_balance_helper=======
26524  /// Helper function to get the required nodal information from an
26525  /// haloed node so that a fully-functional halo node (and therefore element)
26526  /// can be created on the receiving process
26527  //========================================================================
26528  template<class ELEMENT>
26531  Vector<Vector<FiniteElement*> > &f_halo_ele_pt,
26532  unsigned& iproc,
26533  Node* nod_pt)
26534  {
26535  unsigned my_rank = this->communicator_pt()->my_rank();
26536  const unsigned nproc = this->communicator_pt()->nproc();
26537 
26538  // Tell the halo copy of this node how many values there are
26539  // [NB this may be different for nodes within the same element, e.g.
26540  // when using Lagrange multipliers]
26541  unsigned n_val=nod_pt->nvalue();
26542  Flat_packed_unsigneds.push_back(n_val);
26543 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26544  Flat_packed_unsigneds_string.push_back("Number of values");
26545 #endif
26546 
26547  unsigned n_dim=nod_pt->ndim();
26548 
26549  // Default number of previous values to 1
26550  unsigned n_prev=1;
26551  if (this->Time_stepper_pt!=0)
26552  {
26553  // Add number of history values to n_prev
26554  n_prev=this->Time_stepper_pt->ntstorage();
26555  }
26556 
26557  // -----------------------------------------------------
26558  // Is the node on an original boundary?
26559  // Store the original boundaries where the node may be
26560  Vector<unsigned> original_boundaries;
26561  // Loop over the original boundaries of the mesh and check if live
26562  // on one of them
26563  const unsigned n_bnd = this->initial_shared_boundary_id();
26564  for (unsigned bb=0;bb<n_bnd;bb++)
26565  {
26566  // Which boundaries (could be more than one) is it on?
26567  if (nod_pt->is_on_boundary(bb))
26568  {
26569  original_boundaries.push_back(bb);
26570  }
26571 
26572  }
26573 
26574  const unsigned n_original_boundaries = original_boundaries.size();
26575  // Is the node on any original boundary?
26576  if (n_original_boundaries > 0)
26577  {
26578  // Indicate that the node is on an original boundary
26579  Flat_packed_unsigneds.push_back(2);
26580 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26581  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
26582 #endif
26583 
26584  Flat_packed_unsigneds.push_back(n_original_boundaries);
26585 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26586  std::stringstream junk;
26587  junk << "Node is on "<< n_original_boundaries << " original boundaries";
26588  Flat_packed_unsigneds_string.push_back(junk.str());
26589 #endif
26590 
26591  // Loop over the original boundaries the node is on
26592  for (unsigned i=0;i<n_original_boundaries;i++)
26593  {
26594  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26595 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26596  std::stringstream junk;
26597  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
26598  Flat_packed_unsigneds_string.push_back(junk.str());
26599 #endif
26600  // Get the boundary coordinate of the node
26601  Vector<double> zeta(1);
26602  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
26603  Flat_packed_doubles.push_back(zeta[0]);
26604  }
26605  }
26606  else
26607  {
26608  // Indicate that the node is NOT on an original boundary
26609  Flat_packed_unsigneds.push_back(0);
26610 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26611  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
26612 #endif
26613  }
26614 
26615  // -------------------------------------------------------
26616  // Is the node on shared boundaries?
26617  bool node_on_shared_boundary = false;
26618  // Loop over the shared boundaries with the iproc processors and
26619  // check if live on one of them
26620  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26621  for (unsigned bb=0;bb<n_shd_bnd;bb++)
26622  {
26623  // Get the boundary id
26624  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26625  // Which boundaries (could be more than one) is it on?
26626  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26627  {
26628  node_on_shared_boundary = true;
26629  break;
26630  }
26631  }
26632 
26633  // If the node live on any of the shared boundaries with the iproc
26634  // processor then just get the node number according to the
26635  // sorted_shared_boundary_node_pt() scheme and send it accross
26636  if (node_on_shared_boundary)
26637  {
26638  Flat_packed_unsigneds.push_back(1);
26639 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26640  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26641 #endif
26642 
26643  // Store the shared boundaries where the node is on
26644  Vector<unsigned> shd_boundaries;
26645  // Loop over the shared boundaries with the iproc processor
26646  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26647  {
26648  // Get the boundary id
26649  const unsigned i_bnd =
26650  this->shared_boundaries_ids(my_rank, iproc, bb);
26651  // Which boundaries (could be more than one) is it on?
26652  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26653  {
26654  shd_boundaries.push_back(i_bnd);
26655  }
26656  }
26657 
26658  // Get the number of shared boundaries the node is on
26659  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26660  // Send the number of shared boundaries the node is on
26661  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26662 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26663  std::stringstream junk;
26664  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
26665  Flat_packed_unsigneds_string.push_back(junk.str());
26666 #endif
26667 
26668  // Loop over the shared boundaries to send their ids
26669  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
26670  {
26671  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26672 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26673  std::stringstream junk;
26674  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26675  Flat_packed_unsigneds_string.push_back(junk.str());
26676 #endif
26677  }
26678 
26679  // Given that the node is on at least one boundary get the index
26680  // of the node in one of the boundaries and send this index
26681  unsigned shared_boundary_id = shd_boundaries[0];
26682  // Get the number of nodes on the given shared boundary
26683  const unsigned n_nodes_on_shared_boundary =
26684  nsorted_shared_boundary_node(shared_boundary_id);
26685  // Store the index of the node on the shared boundary
26686  unsigned index_node_on_shared_boundary;
26687 #ifdef PARANOID
26688  // Flag to know if the node has been found
26689  bool found_index_node_on_shared_boundary = false;
26690 #endif
26691  // Loop over the nodes on the shared boundary to find the node
26692  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26693  {
26694  // Get the i-th node on the shared boundary
26695  Node* shared_node_pt =
26696  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26697  // Is the node we are looking for
26698  if (shared_node_pt == nod_pt)
26699  {
26700  // Store the index
26701  index_node_on_shared_boundary = i;
26702 #ifdef PARANOID
26703  // Mark as found
26704  found_index_node_on_shared_boundary = true;
26705 #endif
26706  break; // break
26707  }
26708 
26709  } // for (i < nnodes_on_shared_boundary)
26710 
26711 #ifdef PARANOID
26712  if (!found_index_node_on_shared_boundary)
26713  {
26714  std::ostringstream error_message;
26715  error_message
26716  <<"The index of the node on boundary ("
26717  <<shared_boundary_id<<") was not found.\n"
26718  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26719  <<nod_pt->x(1)<<").\n";
26720  throw OomphLibError(
26721  error_message.str(),
26722  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26723  OOMPH_EXCEPTION_LOCATION);
26724  }
26725 #endif
26726  // Send the index of the node on the shared boundary
26727  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
26728 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26729  std::stringstream junk2;
26730  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
26731  <<index_node_on_shared_boundary;
26732  Flat_packed_unsigneds_string.push_back(junk2.str());
26733 #endif
26734 
26735  } // if (node_on_shared_boundary)
26736  else
26737  {
26738  // The node is not on a shared boundary
26739  Flat_packed_unsigneds.push_back(0);
26740 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26741  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
26742 #endif
26743  }
26744 
26745  // ----------------------------------------------------------------
26746  // Is the node on any shared boundary where the receiver processor
26747  // is not involved?
26748 
26749  // Now check if the node is on a shared boundary created by the
26750  // current processor (my_rank) and other processor different that
26751  // the iproc processor. This info. will help to complete the sending
26752  // of halo(ed) information between processors
26753 
26754  // Flag to know if the node is on a shared boundary with other
26755  // processor
26756  bool node_on_shared_boundary_with_other_processors = false;
26757  // Count the number of other shared boundaries it could be on
26758  unsigned nshared_boundaries_with_other_processors_have_node = 0;
26759 
26760  // Loop over the shared boundaries of the sent processor (my_rank)
26761  // and other processors (jproc)
26762  for (unsigned jproc = 0; jproc < nproc; jproc++)
26763  {
26764  // Do not search with the iproc processor, that was done before
26765  // above
26766  if (jproc != iproc)
26767  {
26768  // Get the number of shared boundaries with the jproc processor
26769  const unsigned n_jshd_bnd =
26770  this->nshared_boundaries(my_rank, jproc);
26771  // Loop over the shared boundaries
26772  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
26773  {
26774  // Get the boundary id
26775  const unsigned j_shd_bnd =
26776  this->shared_boundaries_ids(my_rank, jproc, bb);
26777  // Is the node part of this boundary?
26778  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26779  {
26780 // DEBP("Sending to");
26781 // DEBP(iproc);
26782 // DEBP("Pair of procs where other shared");
26783 // DEBP(my_rank);
26784 // DEBP(jproc);
26785 // DEBP(i_bnd);
26786  node_on_shared_boundary_with_other_processors = true;
26787  // Increase the counter for the number of shared boundaries
26788  // with other processors the node is on
26789  nshared_boundaries_with_other_processors_have_node++;
26790  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
26791 
26792  } // for (bb<n_jshd_bnd)
26793 
26794  } // if (jproc != iproc)
26795 
26796  } // for (jproc < nproc)
26797 
26798  // If the node is on a shared boundary with another processor
26799  // (my_rank, jproc), then send the flag and look for the info.
26800  if (node_on_shared_boundary_with_other_processors)
26801  {
26802  Flat_packed_unsigneds.push_back(4);
26803 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26804  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
26805 #endif
26806 
26807  // The number of packages of information that will be sent to the
26808  // "iproc" processor. This helps to know how many packages of data
26809  // read from the received processor
26810  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
26811 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26812  std::stringstream junk;
26813  junk << "Number of other shared boundaries that the node is on: "
26814  << nshared_boundaries_with_other_processors_have_node;
26815  Flat_packed_unsigneds_string.push_back(junk.str());
26816 #endif
26817 
26818  // Counter to ensure that the correct number of data has been sent
26819  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
26820  // Loop over the shared boundaries with other processors and get:
26821  // 1) The processors defining the shared boundary
26822  // 2) The shared boundary id
26823  // 3) The index of the node on the shared boundary
26824  Vector<unsigned> other_processor_1;
26825  Vector<unsigned> other_processor_2;
26826  Vector<unsigned> shd_bnd_ids;
26827  Vector<unsigned> indexes;
26828  // Loop over the processors again
26829  for (unsigned jproc = 0; jproc < nproc; jproc++)
26830  {
26831  // Do not search with the iproc processor, that was done before
26832  // above
26833  if (jproc != iproc)
26834  {
26835  // Get the number of shared boundaries with the jproc
26836  // processor
26837  const unsigned n_jshd_bnd =
26838  this->nshared_boundaries(my_rank, jproc);
26839  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
26840  {
26841  // Get the boundary id
26842  const unsigned j_shd_bnd =
26843  this->shared_boundaries_ids(my_rank, jproc, bb);
26844  // Is the node part of this boundary?
26845  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26846  {
26847  // Include the first processor
26848  other_processor_1.push_back(my_rank);
26849  // Include the second processor
26850  other_processor_2.push_back(jproc);
26851  // Include the shared boundary id
26852  shd_bnd_ids.push_back(j_shd_bnd);
26853  // Increase the counter for found shared boundaries with
26854  // other processors
26855  counter_shd_bnd_with_other_procs_have_node++;
26856  }
26857 
26858  } // for (bb < nshared_bnd)
26859 
26860  } // if (jproc != iproc)
26861 
26862  } // for (jproc < nproc)
26863 
26864  // Get the indexes of the node on all the shared boundaries where
26865  // it was found
26866  const unsigned n_other_processors = other_processor_1.size();
26867  // Loop over the processors where the node was found
26868  for (unsigned i = 0; i < n_other_processors; i++)
26869  {
26870  // Get the shared boundary id
26871  unsigned shd_bnd_id = shd_bnd_ids[i];
26872  // Get the number of nodes on that shared boundary
26873  const unsigned n_nodes_on_shd_bnd =
26874  nsorted_shared_boundary_node(shd_bnd_id);
26875 
26876 #ifdef PARANOID
26877  bool found_index_node_on_shared_boundary = false;
26878 #endif
26879  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
26880  {
26881  // Get the i-th shared boundary node
26882  Node* shared_node_pt =
26883  sorted_shared_boundary_node_pt(shd_bnd_id, i);
26884  // Is the same node?
26885  if (shared_node_pt == nod_pt)
26886  {
26887 // DEBP(i_node);
26888 // DEBP(nod_pt->x(0));
26889 // DEBP(nod_pt->x(1));
26890  // Include the index of the node
26891  indexes.push_back(i);
26892 #ifdef PARANOID
26893  // Mark as found the node
26894  found_index_node_on_shared_boundary = true;
26895 #endif
26896  break;
26897  } // if (shared_node_pt == nod_pt)
26898 
26899  } // for (i < n_nodes_on_shd_bnd)
26900 
26901 #ifdef PARANOID
26902  if (!found_index_node_on_shared_boundary)
26903  {
26904  std::ostringstream error_message;
26905  error_message
26906  <<"The index of the node on boundary ("
26907  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
26908  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26909  <<nod_pt->x(1)<<").\n";
26910  throw OomphLibError(
26911  error_message.str(),
26912  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26913  OOMPH_EXCEPTION_LOCATION);
26914  }
26915 #endif
26916  } // for (i < n_other_processors)
26917 
26918  // Now send the info. but first check that the number of found
26919  // nodes be the same that the previously found shared boundaries
26920  // with the node
26921 #ifdef PARANOID
26922  if (counter_shd_bnd_with_other_procs_have_node !=
26923  nshared_boundaries_with_other_processors_have_node)
26924  {
26925  std::ostringstream error_message;
26926  error_message
26927  <<"The number of shared boundaries where the node is on "
26928  <<"is different:\n"
26929  << "nshared_boundaries_with_other_processors_have_node: ("
26930  << nshared_boundaries_with_other_processors_have_node
26931  << ")\n"
26932  << "counter_shd_bnd_with_other_procs_have_node: ("
26933  << counter_shd_bnd_with_other_procs_have_node
26934  << ")\n";
26935  throw OomphLibError(
26936  error_message.str(),
26937  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26938  OOMPH_EXCEPTION_LOCATION);
26939  } // if (counter_shd_bnd_with_other_procs_have_node !=
26940  // nshared_boundaries_with_other_processors_have_node)
26941 #endif
26942 
26943  // Loop over the info. to send it
26944  for (unsigned i = 0; i < n_other_processors; i++)
26945  {
26946  Flat_packed_unsigneds.push_back(other_processor_1[i]);
26947 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26948  std::stringstream junk1;
26949  junk1 << "Processor where the other shared boundary "
26950  << "has the node: " << other_processor_1[i];
26951  Flat_packed_unsigneds_string.push_back(junk1.str());
26952 #endif
26953 
26954  Flat_packed_unsigneds.push_back(other_processor_2[i]);
26955 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26956  std::stringstream junk2;
26957  junk2 << "Processor where the other shared boundary "
26958  << "has the node: " << other_processor_2[i];
26959  Flat_packed_unsigneds_string.push_back(junk2.str());
26960 #endif
26961 
26962  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
26963 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26964  std::stringstream junk3;
26965  junk3 << "Other shared boundary id where the node is on"
26966  << boundaries[i];
26967  Flat_packed_unsigneds_string.push_back(junk3.str());
26968 #endif
26969 
26970  Flat_packed_unsigneds.push_back(indexes[i]);
26971 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26972  std::stringstream junk4;
26973  junk4 << "Node index on other shared boundary "
26974  <<boundaries[i] << " is "
26975  << indexes[i];
26976  Flat_packed_unsigneds_string.push_back(junk4.str());
26977 #endif
26978 
26979  } // for (i < n_other_processors)
26980 
26981  } // if (node_on_shared_boundary_with_other_processors)
26982  else
26983  {
26984  Flat_packed_unsigneds.push_back(0);
26985 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26986  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
26987 #endif
26988  } // else if (node_on_shared_boundary_with_other_processors)
26989 
26990  // It may still be possible that the node be shared with the
26991  // processor that receives the info. but it is neither on shared
26992  // boundary with the receiver processor nor on a shared boundary
26993  // with others processors. Think in the next case:
26994 
26995  // |-----|-----| - The elements in processor 3 need to be sent to
26996  // | 4 | 3 | processor 1, and that is all
26997  // |-----*-----| - When processor 1 receives the data from node (*)
26998  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
26999  // |-----|-----| that the node is also on the shared boundary that
27000  // processor 1 and 2 or processor 1 and 4 share.
27001 
27002  // This problem become even worse if there would be more processors
27003  // between processor 3 and 2, or/and processor 3 and 4. Think in
27004  // triangles sharing the node (*)
27005 
27006  // To solve this check if the node that we are trying to send is
27007  // part of the halo elements of the curreent processor (my_rank)
27008  // with any other processor (we need to check with all the
27009  // processors and not just with the processors to which we will send
27010  // to cover more cases)
27011 
27012  // Store the halo element number with jproc where the node was found
27013  Vector<Vector<unsigned> > halo_element_number(nproc);
27014  // Store the node number on the halo element where the node was found
27015  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27016 
27017  // Loop over the processor
27018  for (unsigned jproc = 0; jproc < nproc; jproc++)
27019  {
27020  // Get the number of halo elements with the jproc processor
27021  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27022  // Loop over the halo elements
27023  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27024  {
27025  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27026  // Get the number of nodes of the halo element
27027  const unsigned n_node = halo_ele_pt->nnode();
27028  // Loop over the nodes
27029  for (unsigned n = 0; n < n_node; n++)
27030  {
27031  // Is the node part of the ih-th halo element with jproc
27032  if (nod_pt == halo_ele_pt->node_pt(n))
27033  {
27034  halo_element_number[jproc].push_back(jh);
27035  halo_node_number_in_halo_element[jproc].push_back(n);
27036  // break with the nodes, no need to look for more nodes in
27037  // the element
27038  break;
27039  } // if (nod_pt == halo_ele_pt->node_pt(n))
27040 
27041  } // for (n < n_node)
27042 
27043  } // for (jh < n_halo_jproc)
27044 
27045  } // for (jproc < nproc)
27046 
27047  // Send the info. related with if the node is on halo elements with
27048  // any processor
27049 
27050  // Loop over the processors
27051  for (unsigned jproc = 0; jproc < nproc; jproc++)
27052  {
27053  // Get the number of halo elements with jproc processor where the
27054  // node is
27055  const unsigned n_jproc_halo_ele_node_is_on =
27056  halo_element_number[jproc].size();
27057  // Send the number of halo elements with jproc where the node is
27058  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27059 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27060  std::stringstream junk5;
27061  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27062  << "elements with " << jproc << "-th processor";
27063  Flat_packed_unsigneds_string.push_back(junk5.str());
27064 #endif
27065  // Send the halo elements indexes (which will be haloed elements
27066  // indexes in the receiver processor), and the indexes of the
27067  // nodes in each halo element
27068  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27069  {
27070  // The halo element index
27071  const unsigned halo_element_index = halo_element_number[jproc][i];
27072  Flat_packed_unsigneds.push_back(halo_element_index);
27073 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27074  std::stringstream junk6;
27075  junk6 << "Halo element index is ("<<halo_element_index
27076  <<") with processor ("<<jproc<<")";
27077  Flat_packed_unsigneds_string.push_back(junk6.str());
27078 #endif
27079  // The node index on the halo element
27080  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27081  Flat_packed_unsigneds.push_back(node_index);
27082 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27083  std::stringstream junk7;
27084  junk7 << "The node index on the halo element index is ("
27085  << node_index;
27086  Flat_packed_unsigneds_string.push_back(junk7.str());
27087 #endif
27088 
27089  } // for (i < n_jproc_halo_ele_node_is_on)
27090 
27091  } // for (jproc < nproc)
27092 
27093  // Now check if it is required to send the info. of the node. If the
27094  // node is not on a shared boundary with the iproc processor then we
27095  // need to send the info.
27096 
27097  // Flag to indicate if it is on a halo element with the iproc
27098  // processor. If this flag is true then there is no need to send the
27099  // info. to create the node, in the receiver processor the info is
27100  // copied from the indicated haloed element-node
27101  bool on_halo_element_with_iproc_processor = false;
27102  if (halo_element_number[iproc].size() > 0)
27103  {
27104  on_halo_element_with_iproc_processor = true;
27105  } // if (halo_element_number[iproc].size() > 0)
27106 
27107  // if (!node_on_shared_boundary)
27108  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27109  {
27110  // Send all the info. to create it
27111 
27112  // Is the Node algebraic? If so, send its ref values and
27113  // an indication of its geometric objects if they are stored
27114  // in the algebraic mesh
27115  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
27116  if (alg_nod_pt!=0)
27117  {
27118  // The external mesh should be algebraic
27119  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
27120 
27121  // Get default node update function ID
27122  unsigned update_id=alg_nod_pt->node_update_fct_id();
27123  Flat_packed_unsigneds.push_back(update_id);
27124 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27125  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27126 #endif
27127 
27128  // Get reference values at default...
27129  unsigned n_ref_val=alg_nod_pt->nref_value();
27130  Flat_packed_unsigneds.push_back(n_ref_val);
27131 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27132  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27133 #endif
27134  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
27135  {
27136  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27137  }
27138 
27139  // Access geometric objects at default...
27140  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
27141  Flat_packed_unsigneds.push_back(n_geom_obj);
27142 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27143  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27144 #endif
27145  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
27146  {
27147  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
27148 
27149  // Check this against the stored geometric objects in mesh
27150  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
27151 
27152  // Default found index to zero
27153  unsigned found_geom_object=0;
27154  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
27155  {
27156  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
27157  {
27158  found_geom_object=i_list;
27159  }
27160  }
27161  Flat_packed_unsigneds.push_back(found_geom_object);
27162 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27163  Flat_packed_unsigneds_string.push_back("Found geom object");
27164 #endif
27165  }
27166  } // (if alg_nod_pt!=0)
27167 
27168  // Is it a SolidNode?
27169  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
27170  if (solid_nod_pt!=0)
27171  {
27172  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
27173  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
27174  {
27175  for (unsigned t=0;t<n_prev;t++)
27176  {
27177  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
27178  value(t,i_val));
27179  }
27180  }
27181 
27182  Vector<double> values_solid_node;
27183  solid_nod_pt->add_values_to_vector(values_solid_node);
27184  const unsigned nvalues_solid_node = values_solid_node.size();
27185  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27186 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27187  std::stringstream junk;
27188  junk << "Number of values solid node: "
27189  << nvalues_solid_node;
27190  Flat_packed_unsigneds_string.push_back(junk.str());
27191 #endif
27192  for (unsigned i = 0; i < nvalues_solid_node; i++)
27193  {
27194  Flat_packed_doubles.push_back(values_solid_node[i]);
27195  }
27196  }
27197 
27198  // Finally copy info required for all node types
27199  for (unsigned i_val=0;i_val<n_val;i_val++)
27200  {
27201  for (unsigned t=0;t<n_prev;t++)
27202  {
27203  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
27204  }
27205  }
27206 
27207  // Now do positions
27208  for (unsigned idim=0;idim<n_dim;idim++)
27209  {
27210  for (unsigned t=0;t<n_prev;t++)
27211  {
27212  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
27213 // DEBP(nod_pt->x(t,idim));
27214  }
27215  }
27216 
27217  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27218 
27219  }
27220 
27221  //======================================================================
27222  /// \short Helper function to create elements on the loop
27223  /// process based on the info received in
27224  /// send_and_received_elements_nodes_info
27225  //======================================================================
27226  template <class ELEMENT>
27228  unsigned& iproc,
27229  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27230  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27231  &received_old_haloed_element_pt,
27232  Vector<FiniteElement*> &new_elements_on_domain,
27233  Vector<Node*> &new_nodes_on_domain,
27234  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27235  &other_proc_shd_bnd_node_pt,
27236  Vector<Vector<Vector<unsigned> > > &global_node_names,
27237  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27238  Vector<Node*> &global_shared_node_pt)
27239  {
27240 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27241  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27242  << " Bool: New element needs to be constructed "
27243  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27244  << std::endl;
27245 #endif
27246 
27247  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27248  {
27249  // Create a new element from the communicated values
27250  // and coords from the process that located zeta
27251  GeneralisedElement *new_el_pt= new ELEMENT;
27252 
27253  // Add the new element to the mesh - Do not add the element yet
27254  // since no retained elements still need to be deleted
27255  // this->add_element_pt(new_el_pt);
27256 
27257  // Cast to the FE pointer
27258  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
27259 
27260  // Add the element to the new elements in the domain container
27261  new_elements_on_domain.push_back(f_el_pt);
27262 
27263  // Set any additional information for the element
27264  this->add_element_load_balance_helper(iproc,
27265  received_old_haloed_element_pt,
27266  f_el_pt);
27267 
27268  // Add nodes to the new element
27269  unsigned n_node=f_el_pt->nnode();
27270  for (unsigned j=0;j<n_node;j++)
27271  {
27272  Node* new_nod_pt=0;
27273 
27274  // Call the add halo node helper function
27275  add_received_node_load_balance_helper(new_nod_pt,
27276  f_haloed_ele_pt,
27277  received_old_haloed_element_pt,
27278  new_nodes_on_domain,
27279  other_proc_shd_bnd_node_pt,
27280  iproc, j, f_el_pt,
27281  global_node_names,
27282  node_name_to_global_index,
27283  global_shared_node_pt);
27284  }
27285  }
27286  else // the element already exists
27287  {
27288 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27289  oomph_info
27290  << "Rec:" << Counter_for_flat_packed_unsigneds
27291  << " Index of existing element "
27292  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27293  << std::endl;
27294 #endif
27295 
27296  // Incrase the index, we do anything else with the element
27297  Counter_for_flat_packed_unsigneds++;
27298 
27299  } // else the element already exists
27300 
27301  }
27302 
27303  //========start of add_element_load_balance_helper=====================
27304  /// \short Helper function to create elements on the loop
27305  /// process based on the info received in
27306  /// send_and_received_elements_nodes_info
27307  /// This function is in charge of verify if the element is associated
27308  /// to a boundary and associate to it if that is the case
27309  //======================================================================
27310  template<class ELEMENT>
27312  add_element_load_balance_helper(const unsigned &iproc,
27313  Vector<Vector<std::map<
27314  unsigned,FiniteElement*> > >
27315  &received_old_haloed_element_pt,
27316  FiniteElement* ele_pt)
27317  {
27318  // Get the number of processors
27319  const unsigned nproc = this->communicator_pt()->nproc();
27320 
27321 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27322  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27323  << " Bool: Element is associated to a boundary "
27324  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27325  << std::endl;
27326 #endif
27327 
27328  // Is on an original boundary?
27329  const unsigned is_on_original_boundary =
27330  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27331  if (is_on_original_boundary == 1)
27332  {
27333 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27334  oomph_info
27335  << "Rec:" << Counter_for_flat_packed_unsigneds
27336  << " How many boundaries are associated with the element "
27337  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27338  << std::endl;
27339 #endif
27340  // Number of boundaries the element is associated with
27341  const unsigned nassociated_boundaries =
27342  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27343 
27344  // Loop over the associated boundaries
27345  for (unsigned b = 0; b < nassociated_boundaries; b++)
27346  {
27347 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27348  oomph_info
27349  << "Rec:" << Counter_for_flat_packed_unsigneds
27350  << " Boundary associated to the element "
27351  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27352  << std::endl;
27353 #endif
27354 
27355  // The boundary id
27356  const unsigned bnd =
27357  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27358 
27359 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27360  oomph_info
27361  << "Rec:" << Counter_for_flat_packed_unsigneds
27362  << " Face index of the element "
27363  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27364  << std::endl;
27365 #endif
27366 
27367  // The face index
27368  const unsigned face_index =
27369  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27370 
27371  // Associate the element with the boundary and establish as many
27372  // face indexes it has
27373  this->Boundary_element_pt[bnd].push_back(ele_pt);
27374  this->Face_index_at_boundary[bnd].push_back(face_index);
27375 
27376  } // (b < nassociated_boundaries)
27377 
27378  // Here read the info. regarding the boundary-region of the element
27379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27380  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27381  << " Bool: Element is associated to a boundary-region "
27382  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27383  << std::endl;
27384 #endif
27385 
27386  // Is the element associated to a boundary-region?
27387  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27388  {
27389 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27390  oomph_info
27391  << "Rec:" << Counter_for_flat_packed_unsigneds
27392  << " How many boundaries-regions are associated with the element "
27393  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27394  << std::endl;
27395 #endif
27396  // Number of boundary-regions the element is associated
27397  const unsigned nassociated_boundaries_and_regions =
27398  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27399 
27400  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27401  {
27402 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27403  oomph_info
27404  << "Rec:" << Counter_for_flat_packed_unsigneds
27405  << " Boundary associated to the element "
27406  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27407  << std::endl;
27408 #endif
27409  // The boundary id
27410  const unsigned bnd =
27411  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27412 
27413 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27414  oomph_info
27415  << "Rec:" << Counter_for_flat_packed_unsigneds
27416  << " Region associated to the element "
27417  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27418  << std::endl;
27419 #endif
27420  // The region id
27421  const unsigned region =
27422  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27423 
27424 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27425  oomph_info
27426  << "Rec:" << Counter_for_flat_packed_unsigneds
27427  << " Face index of the element in boundary-region "
27428  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27429  << std::endl;
27430 #endif
27431  const unsigned face_index =
27432  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27433 
27434  // Associate the element with the boundary-regions and establish
27435  // as many face indexes it has
27436  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27437  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
27438 
27439  } // for (br < nassociated_boundaries_and_regions)
27440 
27441  } // Is the element associated with a boundary-region?
27442 
27443  } // The element is associated with an original boundary
27444 #ifdef PARANOID
27445  else
27446  {
27447  if (is_on_original_boundary != 0)
27448  {
27449  std::ostringstream error_message;
27450  error_message
27451  <<"The current element is not on an original boundary, this should\n"
27452  <<"be indicated by a zero flag. However, the read value for\n"
27453  <<"that flag is ("<<is_on_original_boundary<<").\n\n";
27454  throw OomphLibError(
27455  error_message.str(),
27456  "RefineableTriangleMesh::add_element_load_balance_helper()",
27457  OOMPH_EXCEPTION_LOCATION);
27458  } // if (is_on_shared_boundary != 0)
27459  }
27460 #endif
27461 
27462 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27463  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27464  << " Bool: Element is associated to a shared boundary "
27465  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27466  << std::endl;
27467 #endif
27468 
27469  // Is the element a shared boundary element?
27470  const unsigned is_on_shared_boundary =
27471  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27472  if (is_on_shared_boundary == 3)
27473  {
27474 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27475  oomph_info
27476  << "Rec:" << Counter_for_flat_packed_unsigneds
27477  << " How many shared boundaries are associated with the element "
27478  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27479  << std::endl;
27480 #endif
27481 
27482  // The number of shared boundaries the element is associated
27483  const unsigned nassociated_shared_boundaries =
27484  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27485 
27486  // Loop over the associated shared boundaries
27487  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27488  {
27489 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27490  oomph_info
27491  << "Rec:" << Counter_for_flat_packed_unsigneds
27492  << " Shared boundary associated to the element "
27493  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27494  << std::endl;
27495 #endif
27496  const unsigned bnd =
27497  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27498 
27499 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27500  oomph_info
27501  << "Rec:" << Counter_for_flat_packed_unsigneds
27502  << " Face index of the element associated to the shared boundary "
27503  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27504  << std::endl;
27505 #endif
27506 
27507  const unsigned face_index =
27508  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27509 
27510  this->add_shared_boundary_element(bnd, ele_pt);
27511  this->add_face_index_at_shared_boundary(bnd, face_index);
27512 
27513  } // (b < nassociated_shared_boundaries)
27514 
27515  } // The element is associted with a shared boundary
27516 #ifdef PARANOID
27517  else
27518  {
27519  if (is_on_shared_boundary != 0)
27520  {
27521  std::ostringstream error_message;
27522  error_message
27523  <<"The current element is not on a shared boundary, this should\n"
27524  <<"be indicated by a zero flag. However, the read value for\n"
27525  <<"that flag is ("<<is_on_shared_boundary<<").\n\n";
27526  throw OomphLibError(
27527  error_message.str(),
27528  "RefineableTriangleMesh::add_element_load_balance_helper()",
27529  OOMPH_EXCEPTION_LOCATION);
27530  } // if (is_on_shared_boundary != 0)
27531  }
27532 #endif
27533 
27534  // Now check if the element is a haloed element in the sender
27535  // processor with any other processor
27536 
27537  // Loop over the processors
27538  for (unsigned jproc = 0; jproc < nproc; jproc++)
27539  {
27540 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27541  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27542  << " Bool: Number of haloed indexes of the element with the "
27543  << jproc << " processor: "
27544  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27545  << std::endl;
27546 #endif
27547  // Is the element haloed with the jproc processor
27548  const unsigned n_index_haloed_jproc =
27549  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27550  // Loop over the number of haloed indexes
27551  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27552  {
27553 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27554  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27555  << " Bool: The haloed element index with the "
27556  << jproc << " processor: "
27557  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27558  << std::endl;
27559 #endif
27560  const unsigned haloed_index =
27561  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27562 
27563  // Set the halod element in the proper storage
27564  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27565 
27566  } // for (ihd < n_index_haloed_jproc)
27567 
27568  } // for (jproc < nproc)
27569 
27570  }
27571 
27572  //======================================================================
27573  /// \short Helper function to add a new node from load balance
27574  //======================================================================
27575  template <class ELEMENT>
27578  Vector<Vector<FiniteElement*> >
27579  &f_haloed_ele_pt,
27580  Vector<Vector<std::map<
27581  unsigned,FiniteElement*> > >
27582  &received_old_haloed_element_pt,
27583  Vector<Node*> &new_nodes_on_domain,
27584  Vector<Vector<Vector<
27585  std::map<unsigned, Node*> > > >
27586  &other_proc_shd_bnd_node_pt,
27587  unsigned& iproc,
27588  unsigned& node_index,
27589  FiniteElement* const &new_el_pt,
27590  Vector<Vector<Vector<unsigned> > >
27591  &global_node_names,
27592  std::map<Vector<unsigned>, unsigned>
27593  &node_name_to_global_index,
27594  Vector<Node*> &global_shared_node_pt)
27595  {
27596  // Given the node, received information about it from processor
27597  // iproc, construct it on the current process
27598 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27599  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27600  << " Bool: New node needs to be constructed "
27601  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27602  << std::endl;
27603 #endif
27604  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27605  {
27606  // Construct a new node based upon sent information, or copy a node
27607  // from one of the shared boundaries
27608  construct_new_node_load_balance_helper(new_nod_pt,
27609  f_haloed_ele_pt,
27610  received_old_haloed_element_pt,
27611  new_nodes_on_domain,
27612  other_proc_shd_bnd_node_pt,
27613  iproc,
27614  node_index,
27615  new_el_pt,
27616  global_node_names,
27617  node_name_to_global_index,
27618  global_shared_node_pt);
27619  }
27620  else
27621  {
27622 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27623  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27624  << " Index of existing halo node "
27625  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27626  << std::endl;
27627 #endif
27628  // The node already exist, copy it from the indicated position
27629 
27630  // Get the node's index, and copy it
27631  new_nod_pt = new_nodes_on_domain[
27632  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
27633 
27634  // Set the node in the current element
27635  new_el_pt->node_pt(node_index) = new_nod_pt;
27636 
27637  }
27638 
27639  }
27640 
27641  //============start_of_construct_new_node_load_balance_helper()=========
27642  /// \short Helper function which constructs a new node (on an
27643  /// element) with the information sent from the load balance
27644  /// process
27645  //======================================================================
27646  template<class ELEMENT>
27649  Node* &new_nod_pt,
27650  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27651  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27652  &received_old_haloed_element_pt,
27653  Vector<Node*> &new_nodes_on_domain,
27654  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27655  &other_proc_shd_bnd_node_pt,
27656  unsigned& iproc, unsigned& node_index,
27657  FiniteElement* const &new_el_pt,
27658  Vector<Vector<Vector<unsigned> > > &global_node_names,
27659  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27660  Vector<Node*> &global_shared_node_pt)
27661  {
27662  // Get the number of processors
27663  const unsigned nproc = this->communicator_pt()->nproc();
27664  // Get the rank of the current processor
27665  const unsigned my_rank = this->communicator_pt()->my_rank();
27666 
27667  //The first entry indicates the number of values at this new Node
27668  //(which may be different across the same element e.g. Lagrange multipliers)
27669 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27670  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27671  << " Number of values of external halo node "
27672  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27673  << std::endl;
27674 #endif
27675  unsigned n_val=Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27676 
27677  // Null TimeStepper for now
27678  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
27679  // Default number of previous values to 1
27680  unsigned n_prev=time_stepper_pt->ntstorage();
27681 
27682  // ------------------------------------------------------
27683  // Check if the node is on an original boundary
27684 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27685  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27686  << " Is the node on an original boundary "
27687  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27688  << std::endl;
27689 #endif
27690 
27691  // Flag to indicate if the node is on original boundaries
27692  const unsigned node_on_original_boundaries =
27693  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27694 
27695  // Store the original boundaries where the node is on
27696  Vector<unsigned> original_boundaries_node_is_on;
27697  // Store the zeta coordinates of the node on the original boundaries
27698  Vector<double> zeta_coordinates;
27699  // Store the number of original boundaries the node is on
27700  unsigned n_original_boundaries_node_is_on = 0;
27701 
27702  if (node_on_original_boundaries==2)
27703  {
27704  // How many original boundaries does the node live on?
27705 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27706  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27707  << " Number of boundaries the node is on: "
27708  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27709  << std::endl;
27710 #endif
27711  n_original_boundaries_node_is_on =
27712  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27713 
27714  // Resize the containers
27715  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27716  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27717 
27718  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
27719  {
27720  // Boundary number
27721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27722  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27723  << " Node is on boundary "
27724  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27725  << std::endl;
27726 #endif
27727  original_boundaries_node_is_on[i] =
27728  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27729  zeta_coordinates[i] =
27730  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
27731  }
27732 
27733  } // if (node_on_original_boundaries==2)
27734 #ifdef PARANOID
27735  else
27736  {
27737  if (node_on_original_boundaries != 0)
27738  {
27739  std::ostringstream error_message;
27740  error_message
27741  <<"The current node is not on an original boundary, this should\n"
27742  <<"be indicated by a zero flag. However, the read value for\n"
27743  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
27744  throw OomphLibError(
27745  error_message.str(),
27746  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27747  OOMPH_EXCEPTION_LOCATION);
27748  } // if (node_on_original_boundaries != 0)
27749  }
27750 #endif
27751 
27752  // --------------------------------------------------------------
27753  // Check if the node was on a shared boundary with the iproc
27754  // processor
27755 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27756  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27757  << " Is node on shared boundary? "
27758  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27759  << std::endl;
27760 #endif
27761  const unsigned is_node_on_shared_boundary =
27762  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27763  if (is_node_on_shared_boundary == 1)
27764  {
27765  // How many shared boundaries does the node live on?
27766 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27767  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27768  << " Number of boundaries the node is on: "
27769  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27770  << std::endl;
27771 #endif
27772  const unsigned n_shd_bnd_node_is_on =
27773  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27774  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
27775  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
27776  {
27777  // Shared boundary number
27778 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27779  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27780  << " Node is on boundary "
27781  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27782  << std::endl;
27783 #endif
27784  shd_bnds_node_is_on[i] =
27785  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27786  }
27787 
27788  // Get the index of the node on the shared boundary
27789 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27790  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27791  << " Index of node on boundary "
27792  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27793  << std::endl;
27794 #endif
27795  // Get the node index of the node on the shared boundary
27796  unsigned node_index_on_shared_boundary =
27797  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27798 
27799  // Get the pointer to the node with the received info.
27800  new_nod_pt =
27801  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
27802  node_index_on_shared_boundary);
27803 
27804  } // if (is_node_on_shared_boundary == 1)
27805 #ifdef PARANOID
27806  else
27807  {
27808  if (is_node_on_shared_boundary != 0)
27809  {
27810  std::ostringstream error_message;
27811  error_message
27812  <<"The current node is not on a shared boundary, this should\n"
27813  <<"be indicated by a zero flag. However, the read value for\n"
27814  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
27815  throw OomphLibError(
27816  error_message.str(),
27817  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27818  OOMPH_EXCEPTION_LOCATION);
27819  } // if (node_on_shared_boundary != 0)
27820  }
27821 #endif
27822 
27823  // ------------------------------------------------------------
27824  // Is the node on a shared boundary with other processor?
27825 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27826  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27827  << " Is the node on shared boundaries with other processors "
27828  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27829  << std::endl;
27830 #endif
27831 
27832  // Is the node in shared boundaries no associated with the
27833  // receiver processor
27834  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
27835  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27836 
27837  // The containers where to store the info.
27838  Vector<unsigned> other_processor_1;
27839  Vector<unsigned> other_processor_2;
27840  Vector<unsigned> other_shared_boundaries;
27841  Vector<unsigned> other_indexes;
27842 
27843  // How many shared bounaries with other processors the node lives on
27844  unsigned n_shd_bnd_with_other_procs_have_node = 0;
27845 
27846  // Is the node on shared boundaries with other processors
27847  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27848  {
27849 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27850  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27851  << " In how many shared boundaries with other "
27852  << "processors is the node "
27853  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27854  << std::endl;
27855 #endif
27856 
27857  // How many nodes on other shared boundaries were found
27858  n_shd_bnd_with_other_procs_have_node =
27859  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27860 
27861  // Resize the containers
27862  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
27863  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
27864  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
27865  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
27866 
27867  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
27868  {
27869 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27870  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27871  << " Processor where the other shared boundary"
27872  << "has the node"
27873  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27874  << std::endl;
27875 #endif
27876  // Read the other processor 1
27877  other_processor_1[i] =
27878  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27879 
27880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27881  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27882  << " Processor where the other shared boundary"
27883  << "has the node"
27884  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27885  << std::endl;
27886 #endif
27887  // Read the other processor 2
27888  other_processor_2[i] =
27889  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27890 
27891 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27892  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27893  << " Other shared boundary id where the node is on: "
27894  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27895  << std::endl;
27896 #endif
27897 
27898  // Read the other shared boundary id
27899  other_shared_boundaries[i] =
27900  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27901 
27902 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27903  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27904  << " Node index on the other shared boundary "
27905  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27906  << std::endl;
27907 #endif
27908 
27909  // Read the node index on the other shared boundary
27910  other_indexes[i] =
27911  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27912 
27913  } // for (i < n_shd_bnd_with_other_procs_have_node)
27914 
27915  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27916 #ifdef PARANOID
27917  else
27918  {
27919  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
27920  {
27921  std::ostringstream error_message;
27922  error_message
27923  <<"The current node is not on a shared boundary with\n"
27924  <<"other processors, this should be indicated by a zero flag.\n"
27925  <<"However, the read value for that flag is ("
27926  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
27927  throw OomphLibError(
27928  error_message.str(),
27929  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
27930  OOMPH_EXCEPTION_LOCATION);
27931  }
27932  }
27933 #endif
27934 
27935  // ------------------------------------------------------------
27936  // Receive the info. to check if the node is on a haloed element
27937  // with any processor
27938 
27939  // Store the halo element number with jproc where the node was found
27940  Vector<Vector<unsigned> > halo_element_number(nproc);
27941  // Store the node number on the halo element where the node was found
27942  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27943 
27944  // Loop over the processors
27945  for (unsigned jproc = 0; jproc < nproc; jproc++)
27946  {
27947 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27948  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27949  << " The node is on "
27950  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27951  << " halo elements with " << jproc << " processor"
27952  << std::endl;
27953 #endif
27954  // Get the number of halo elements with jproc processor where the
27955  // node was found
27956  const unsigned n_jproc_halo_ele_node_is_on =
27957  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27958 
27959  // Resize the containers
27960  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
27961  halo_node_number_in_halo_element[jproc].resize(n_jproc_halo_ele_node_is_on);
27962 
27963  // Read halo elements indexes (which are indexes of the halo
27964  // elements of the sender processor (iproc) with other processors
27965  // (included my_rank)
27966  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27967  {
27968  // Get the halo element index in the jproc processor
27969 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27970  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27971  << " The halo element index where the node is on "
27972  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27973  << std::endl;
27974 #endif
27975  // Get the node index on the halo element
27976  const unsigned halo_ele_index =
27977  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27978 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27979  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27980  << " The node index on the halo element where the node "
27981  << "is on "
27982  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27983  << std::endl;
27984 #endif
27985  const unsigned node_index_on_halo_ele =
27986  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27987 
27988  // Store the halo element number
27989  halo_element_number[jproc][i] = halo_ele_index;
27990  // Store the index of on the haloed element
27991  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
27992 
27993  } // for (i < n_jproc_halo_ele_node_is_on)
27994 
27995  } // for (jproc < nproc)
27996 
27997  // Store the node pointers obtained from the indicated halo elements
27998  // (use a set to check for the case when the node pointer is
27999  // different)
28000  std::set<Node*> set_haloed_node_pt;
28001 
28002  // Store the node pointer obtained from the haloed elements
28003  Node* haloed_node_pt = 0;
28004 
28005  // Flag to indicate if it is on a haloed element of the current
28006  // processor with the iproc processor. If this flag is true then
28007  // there is no need to read the info. to create the node, only copy
28008  // the node from the indicated haloed element-node
28009  bool on_haloed_element_with_iproc_processor = false;
28010  if (halo_element_number[my_rank].size() > 0)
28011  {
28012  // The node is part of the haloed element in the current processor
28013  // (my_rank) with the receiver processor
28014  on_haloed_element_with_iproc_processor = true;
28015 
28016  // Get the number of haloed elements in the current processor
28017  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28018  // Loop over the different haloed indexes, and get the nodes
28019  // instances from all the indicated haloed elements (all of them
28020  // should be the same)
28021  for (unsigned i = 0; i < n_haloed_indexes; i++)
28022  {
28023  // Get the haloed element numbers where the node is on
28024  const unsigned haloed_index = halo_element_number[my_rank][i];
28025  // Get the node index on the haloed element
28026  const unsigned haloed_node_index =
28027  halo_node_number_in_halo_element[my_rank][i];
28028 
28029  // Get the haloed element (with iproc)
28030  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28031  // Get the node on the indicated node number
28032  Node* tmp_haloed_node_pt = tmp_haloed_ele_pt->node_pt(haloed_node_index);
28033 
28034  // Set the pointer for the obtained haloed node
28035  haloed_node_pt = tmp_haloed_node_pt;
28036 
28037  // Add the node to the set of node pointers
28038  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28039 
28040 #ifdef PARANOID
28041  if (set_haloed_node_pt.size() > 1)
28042  {
28043  std::ostringstream error_message;
28044  error_message
28045  <<"When adding the " << haloed_node_index << " node of the "
28046  << haloed_index << "-th haloed element\n"
28047  << "in the currrent processor with the " << iproc << " processor"
28048  << "it was found that\nthe node pointer is different from the other"
28049  << "instances of the node.\nIt means we have a repeated node."
28050  << "This are the node coordinates of the previous node instances\n"
28051  << "The last entry is for the just added node with a different node\n"
28052  << "pointer\n";
28053  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28054  it != set_haloed_node_pt.end(); it++)
28055  {
28056  error_message
28057  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28058  }
28059  error_message << "\n";
28060  throw OomphLibError(
28061  error_message.str(),
28062  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28063  OOMPH_EXCEPTION_LOCATION);
28064  }
28065 #endif
28066 
28067  } // for (i < n_haloed_indexes)
28068 
28069  } // if (halo_element_number[iproc].size() > 0)
28070 
28071  // Flag to indicate if the node has been found on a haloed element
28072  // of other processor with the iproc processor
28073  bool found_on_haloed_element_with_other_processor = false;
28074  // Loop over the processors (only until the iproc since no info. of
28075  // higher processors has been received)
28076  for (unsigned jproc = 0; jproc < iproc; jproc++)
28077  {
28078  // Is the node on a halo element with the jproc processor
28079  if (halo_element_number[jproc].size() > 0)
28080  {
28081  // Get the number of halo elements with the jproc processor
28082  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28083  // Loop over the different halo indexes, and get the nodes
28084  // instances from all the indicated halo elements (all of them
28085  // should be the same)
28086  for (unsigned i = 0; i < n_halo_indexes; i++)
28087  {
28088  // Get the haloed element numbers where the node is on
28089  const unsigned haloed_index = halo_element_number[jproc][i];
28090  // Get the node index on the haloed element
28091  const unsigned haloed_node_index =
28092  halo_node_number_in_halo_element[jproc][i];
28093 
28094  // Have we received the indicated element? (Get the haloed
28095  // element on jproc with the iproc processor)
28096  std::map<unsigned,FiniteElement*>::iterator it_map =
28097  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28098  // Have we received the indicated element?
28099  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28100  {
28101  // Set the flag of found element in other processors haloed
28102  // element, in this case in haloed elements of processor
28103  // jproc wiht iproc processor
28104  found_on_haloed_element_with_other_processor = true;
28105 
28106  // Get the element
28107  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28108  // Get the node on the indicated node number
28109  Node* tmp_haloed_node_pt =
28110  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28111 
28112  // Set the pointer for the obtained haloed node
28113  haloed_node_pt = tmp_haloed_node_pt;
28114 
28115  // Add the node to the set of node pointers
28116  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28117 
28118 #ifdef PARANOID
28119  if (set_haloed_node_pt.size() > 1)
28120  {
28121  std::ostringstream error_message;
28122  error_message
28123  <<"When adding the " << haloed_node_index << " node of the "
28124  << haloed_index << "-th haloed element "
28125  << "of the " << jproc << " processor\nwith the "
28126  << iproc << " processor, it was found that\n"
28127  << "the node pointer is different from the other\n"
28128  << "instances of the node.\nThis means we have a repeated node.\n"
28129  << "These are the node coordinates of the previous node "
28130  << "instances\n"
28131  << "The last entry is for the just added node with a different\n"
28132  << "node pointer\n";
28133  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28134  it != set_haloed_node_pt.end(); it++)
28135  {
28136  error_message
28137  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28138  }
28139  error_message << "\n";
28140  throw OomphLibError(
28141  error_message.str(),
28142  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28143  OOMPH_EXCEPTION_LOCATION);
28144  }
28145 #endif
28146 
28147  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28148  // Have we received the element?
28149 
28150  } // for (i < n_haloed_indexes)
28151 
28152  } // if (halo_element_number[iproc].size() > 0)
28153 
28154  } // for (jproc < nproc)
28155 
28156  // If the node was found in the haloed elements of the current
28157  // processor with the iproc processor, or in the haloed elements of
28158  // any other processor with the iproc processor then copy the node
28159  // pointer (no problem if we overwrite the node info. it should be
28160  // the same node pointer)
28161  if (on_haloed_element_with_iproc_processor ||
28162  found_on_haloed_element_with_other_processor)
28163  {
28164  // Set the node pointer
28165  new_nod_pt = haloed_node_pt;
28166  }
28167 
28168  // Now we have all the info. to decide if the node should be created
28169  // or not
28170 
28171  // First check if the node is a shared boundary node, or if it has
28172  // been found on haloed elements
28173  if (is_node_on_shared_boundary == 1 ||
28174  (on_haloed_element_with_iproc_processor))
28175  {
28176  // We already have the node, we do not need to create it
28177 
28178  // Only check if we need to add boundary info. to the node
28179  if (node_on_original_boundaries==2)
28180  {
28181  // The node is a boundary node, add the boundary info. before
28182  // adding it to the domain
28183 
28184  // Associate the node to the given boundaries
28185  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28186  {
28187  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28188  // Establish the boundary coordinates for the node
28189  Vector<double> zeta(1);
28190  zeta[0] = zeta_coordinates[i];
28191  new_nod_pt->set_coordinates_on_boundary(
28192  original_boundaries_node_is_on[i],zeta);
28193  }
28194 
28195  } // if (node_on_original_boundaries==2)
28196 
28197  // Add the node to the domain
28198  new_nodes_on_domain.push_back(new_nod_pt);
28199 
28200  // Add the node to the element
28201  new_el_pt->node_pt(node_index) = new_nod_pt;
28202 
28203  } // if (is_node_on_shared_boundary == 1)
28204 
28205  // Now check if the node is on a shared boundary with another
28206  // processor, if that is the case try to find the node that may have
28207  // been already sent by the other processors
28208 
28209  // This flags indicates if the node was found, and then decide if it
28210  // is required to create the node
28211  bool found_node_in_other_shared_boundaries = false;
28212  // Flag to indicate whether the node should be created as a boundary
28213  // node or not. If the node lies on a shared boundary with other
28214  // processor the we create it as a boundary node. The processor from
28215  // which we are receiving info. (iproc) may not know that the node
28216  // lies on an original boundary. If the node lies on an original
28217  // boundary then its info. will be sent by another processor, then
28218  // we can set its boundary info. since the node was constructed as a
28219  // boundary node
28220  bool build_node_as_boundary_node = false;
28221 
28222  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28223  {
28224  // Build the node as a boundary node
28225  build_node_as_boundary_node = true;
28226 
28227  // Try to get the node pointer in case that the node has been
28228  // already sent by the other processors
28229 
28230  // Get the number of initial shared boundaries to correct the
28231  // index of the shared boundary
28232  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28233 
28234  // Add the found nodes in the container, should be the same but
28235  // better check
28236  Vector<Node*> found_node_pt;
28237 
28238  // Now try to find the node in any of the other shared boundaries
28239  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28240  {
28241  unsigned oproc1 = other_processor_1[i];
28242  unsigned oproc2 = other_processor_2[i];
28243 
28244  // Check that we always check with the lower processors number
28245  // first
28246  if (oproc1 > oproc2)
28247  {
28248  oproc2 = oproc1;
28249  oproc1 = other_processor_2[i];
28250  } // if (oproc1 > oproc2)
28251 
28252  // Re-compute the shared boundary id between the other
28253  // processors
28254  const unsigned shd_bnd_id =
28255  other_shared_boundaries[i] - initial_shd_bnd_id;
28256  // Read the index
28257  const unsigned index = other_indexes[i];
28258 
28259  // Check if there are nodes received from the other processor
28260  // and with the given shared boundary
28261  const unsigned n_nodes_on_other_processor =
28262  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28263 
28264  if (n_nodes_on_other_processor > 0)
28265  {
28266  // Check if we can find the index of the node in that other
28267  // processor and shared boundary id
28268  std::map<unsigned, Node*>::iterator it =
28269  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
28270  find(index);
28271 
28272  // If the index exist then get the node pointer
28273  if (it!=
28274  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28275  {
28276  // Mark the node as found
28277  found_node_in_other_shared_boundaries = true;
28278  // Get the node pointer
28279  Node* tmp_node_pt =
28280  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28281  found_node_pt.push_back(tmp_node_pt);
28282  } // if (it!=
28283  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28284 
28285  } // if (n_nodes_on_other_processor > 0)
28286 
28287  } // for (i < n_shd_bnd_with_other_procs_have_node)
28288 
28289  // If the node was found, then all their instances should be the
28290  // same but better check
28291  if (found_node_in_other_shared_boundaries)
28292  {
28293 #ifdef PARANOID
28294  const unsigned ntimes_node_found = found_node_pt.size();
28295  for (unsigned j = 1; j < ntimes_node_found; j++)
28296  {
28297  if (found_node_pt[j-1] != found_node_pt[j])
28298  {
28299  std::ostringstream error_message;
28300  error_message
28301  <<"The instances of the node that was found to be on a\n"
28302  <<"shared boundary with other processors are not the same,\n"
28303  <<"the coordinates for the nodes are these:\n"
28304  <<"(" << found_node_pt[j-1]->x(0) << ", "
28305  << found_node_pt[j-1]->x(1) << ")\n"
28306  <<"(" << found_node_pt[j]->x(0) << ", "
28307  << found_node_pt[j]->x(1) << ")\n"
28308  <<"Not be surprised if they are the same since the node is\n"
28309  <<"repeated!!!\n";
28310  throw OomphLibError(
28311  error_message.str(),
28312  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28313  OOMPH_EXCEPTION_LOCATION);
28314 
28315  } // if (found_node_pt[j-1] != found_node_pt[j])
28316 
28317  } // for (j < ntimes_node_found)
28318 #endif
28319 
28320  // Check if the node is a shared boundary node from the current
28321  // processor and the iproc processor, if that is the case, and
28322  // the node is also on a shared boundary with other processor,
28323  // then the pointer should be the same!!!
28324  if (is_node_on_shared_boundary == 1)
28325  {
28326  // The pointer to the node is already assigned, it was
28327  // assigned when thenode was found to be on a shared boundary
28328  // with the iproc processor
28329  if (found_node_pt[0] != new_nod_pt)
28330  {
28331  std::ostringstream error_message;
28332  error_message
28333  <<"The pointer of the node that was found to be on a\n"
28334  <<"shared boundary with other processor(s) and the pointer\n"
28335  <<"of the node on shared boundary with the receiver\n"
28336  <<"processor (iproc) are not the same. This means we have a\n"
28337  << "repeated node)\n"
28338  <<"The coordinates for the nodes are:\n"
28339  <<"(" << found_node_pt[0]->x(0) << ", "
28340  << found_node_pt[0]->x(1) << ")\n"
28341  <<"(" << new_nod_pt->x(0) << ", "
28342  << new_nod_pt->x(1) << ")\n"
28343  <<"Not to be surprised if they are the same since the node is\n"
28344  <<"repeated!!!\n";
28345  throw OomphLibError(
28346  error_message.str(),
28347  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28348  OOMPH_EXCEPTION_LOCATION);
28349  } // if (found_node_pt[0] != new_nod_pt)
28350 
28351  } // if (is_node_on_shared_boundary == 1)
28352  else
28353  {
28354  // Take the first instance of the node in case that it was
28355  // found and is not on a shared boundary with the iproc
28356  // processor
28357  new_nod_pt = found_node_pt[0];
28358  }
28359 
28360  } // if (found_node_in_other_shared_boundaries)
28361 
28362  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28363 
28364  // -----------------------------------------------------------------
28365  // Create the node or read the received info if the node is not on a
28366  // shared boundary with the iproc processor and if the node is not
28367  // part of the haloed elements with the iproc processor in the
28368  // current processors
28369  if (is_node_on_shared_boundary != 1 &&
28370  !on_haloed_element_with_iproc_processor)
28371  {
28372  // If the node is on a shared boundary with other processor we
28373  // need to read all the info. since the processor that sent the
28374  // info. did not know that the node is part of another shared
28375  // boundary
28376 
28377  // If the node is not a shared boundary (with any processor), or
28378  // if this is the first time that the info. of the node is
28379  // received from any of the processors with which is has a shared
28380  // boundary, then we create the node
28381 
28382  // Is the node a boundary node or should it be build as a boundary
28383  // node because it is on a shared boundary with other processors
28384  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
28385  {
28386  // Check if necessary to create the node, or if it has been
28387  // already found in shared boundaries with other processors or
28388  // in the haloed elements with of other processors with the
28389  // iproc processor
28390  if (!found_node_in_other_shared_boundaries ||
28391  !found_on_haloed_element_with_other_processor)
28392  {
28393  // Construct a boundary node
28394  if (time_stepper_pt!=0)
28395  {
28396  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
28397  time_stepper_pt);
28398  }
28399  else
28400  {
28401  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
28402  }
28403 
28404  } // if (!found_node_in_other_shared_boundaries ||
28405  // !found_on_haloed_element_with_other_processor)
28406  else
28407  {
28408  // If the node was found then assign the node to the element
28409  new_el_pt->node_pt(node_index) = new_nod_pt;
28410  } // else if (!found_node_in_other_shared_boundaries ||
28411  // !found_on_haloed_element_with_other_processor)
28412 
28413  // Associate the node to the given boundaries
28414  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28415  {
28416  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28417  // Establish the boundary coordinates for the node
28418  Vector<double> zeta(1);
28419  zeta[0] = zeta_coordinates[i];
28420  new_nod_pt->set_coordinates_on_boundary(
28421  original_boundaries_node_is_on[i],zeta);
28422  }
28423 
28424  } // if (node is on an original boundary)
28425  else
28426  {
28427  // Check if necessary to create the node, or if it has been
28428  // already found in shared boundaries with other processors or
28429  // in the haloed elements with of other processors with the
28430  // iproc processor
28431  if (!found_node_in_other_shared_boundaries ||
28432  !found_on_haloed_element_with_other_processor)
28433  {
28434  // Construct an ordinary (non-boundary) node
28435  if (time_stepper_pt!=0)
28436  {
28437  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
28438  }
28439  else
28440  {
28441  new_nod_pt=new_el_pt->construct_node(node_index);
28442  }
28443  } // if (!found_node_in_other_shared_boundaries ||
28444  // !found_on_haloed_element_with_other_processor)
28445  else
28446  {
28447  // If the node was found then assign the node to the element
28448  new_el_pt->node_pt(node_index) = new_nod_pt;
28449  } // else // if (!found_node_in_other_shared_boundaries ||
28450  // !found_on_haloed_element_with_other_processor)
28451 
28452  } // else (the node is not a boundary node)
28453 
28454  // ... and gather all its information
28455 
28456  // If the node was found or not in other shared boundaries, this
28457  // is the first time the node is received from this processor
28458  // (iproc), therefore it is added to the vector of nodes received
28459  // from this processor (iproc)
28460  new_nodes_on_domain.push_back(new_nod_pt);
28461 
28462  // Check if necessary to state all the info. to the node if it has
28463  // been already found in shared boundaries with other processors
28464  // or in the haloed elements with of other processors with the
28465  // iproc processor
28466  if (!found_node_in_other_shared_boundaries ||
28467  !found_on_haloed_element_with_other_processor)
28468  {
28469  // Add the node to the general node storage
28470  this->add_node_pt(new_nod_pt);
28471  } // if (!found_node_in_other_shared_boundaries ||
28472  // !found_on_haloed_element_with_other_processor)
28473 
28474  // Is the new constructed node Algebraic?
28475  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
28476  (new_nod_pt);
28477 
28478  // If it is algebraic, its node update functions will
28479  // not yet have been set up properly
28480  if (new_alg_nod_pt!=0)
28481  {
28482  // The AlgebraicMesh is the external mesh
28483  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
28484 
28485  /// The first entry of All_alg_nodal_info contains
28486  /// the default node update id
28487  /// e.g. for the quarter circle there are
28488  /// "Upper_left_box", "Lower right box" etc...
28489 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28490  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28491  << " Alg node update id "
28492  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28493  << std::endl;
28494 #endif
28495 
28496  unsigned update_id=Flat_packed_unsigneds
28497  [Counter_for_flat_packed_unsigneds++];
28498 
28499  Vector<double> ref_value;
28500 
28501  // The size of this vector is in the next entry
28502  // of All_alg_nodal_info
28503 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28504  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28505  << " Alg node # of ref values "
28506  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28507  << std::endl;
28508 #endif
28509  unsigned n_ref_val=Flat_packed_unsigneds
28510  [Counter_for_flat_packed_unsigneds++];
28511 
28512  // The reference values themselves are in
28513  // All_alg_ref_value
28514  ref_value.resize(n_ref_val);
28515  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
28516  {
28517  ref_value[i_ref]=Flat_packed_doubles
28518  [Counter_for_flat_packed_doubles++];
28519  }
28520 
28521  Vector<GeomObject*> geom_object_pt;
28522  /// again we need the size of this vector as it varies
28523  /// between meshes; we also need some indication
28524  /// as to which geometric object should be used...
28525 
28526  // The size of this vector is in the next entry
28527  // of All_alg_nodal_info
28528 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28529  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28530  << " Alg node # of geom objects "
28531  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28532  << std::endl;
28533 #endif
28534  unsigned n_geom_obj=Flat_packed_unsigneds
28535  [Counter_for_flat_packed_unsigneds++];
28536 
28537  // The remaining indices are in the rest of
28538  // All_alg_nodal_info
28539  geom_object_pt.resize(n_geom_obj);
28540  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
28541  {
28542 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28543  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28544  << " Alg node: geom object index "
28545  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28546  << std::endl;
28547 #endif
28548  unsigned geom_index=Flat_packed_unsigneds
28549  [Counter_for_flat_packed_unsigneds++];
28550  // This index indicates which of the AlgebraicMesh's
28551  // stored geometric objects should be used
28552  // (0 is a null pointer; everything else should have
28553  // been filled in by the specific Mesh). If it
28554  // hasn't been filled in then the update_node_update
28555  // call should fix it
28556  geom_object_pt[i_geom]=alg_mesh_pt->
28557  geom_object_list_pt(geom_index);
28558  }
28559 
28560  // Check if necessary to state all the info. to the node if it
28561  // has been already found in shared boundaries with other
28562  // processors or in the haloed elements with of other processors
28563  // with the iproc processor
28564  if (!found_node_in_other_shared_boundaries ||
28565  !found_on_haloed_element_with_other_processor)
28566  {
28567  /// For the received update_id, ref_value, geom_object
28568  /// call add_node_update_info
28569  new_alg_nod_pt->add_node_update_info
28570  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
28571 
28572  /// Now call update_node_update
28573  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28574 
28575  } // if (!found_node_in_other_shared_boundaries ||
28576  // !found_on_haloed_element_with_other_processor)
28577 
28578  } // if (new_alg_nod_pt!=0)
28579 
28580  // Check if necessary to state all the info. to the node if it has
28581  // been already found in shared boundaries with other processors
28582  // or in the haloed elements with of other processors with the
28583  // iproc processor
28584  if (!found_node_in_other_shared_boundaries ||
28585  !found_on_haloed_element_with_other_processor)
28586  {
28587  // Is the node a MacroElementNodeUpdateNode?
28588  MacroElementNodeUpdateNode* macro_nod_pt=
28589  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28590 
28591  if (macro_nod_pt!=0)
28592  {
28593  // Need to call set_node_update_info; this requires
28594  // a Vector<GeomObject*> (taken from the mesh)
28595  Vector<GeomObject*> geom_object_vector_pt;
28596 
28597  // Access the required geom objects from the
28598  // MacroElementNodeUpdateMesh
28599  MacroElementNodeUpdateMesh* macro_mesh_pt=
28600  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28601  geom_object_vector_pt=
28602  macro_mesh_pt->geom_object_vector_pt();
28603 
28604  // Get local coordinate of node in new element
28605  Vector<double> s_in_macro_node_update_element;
28606  new_el_pt->local_coordinate_of_node
28607  (node_index,s_in_macro_node_update_element);
28608 
28609  // Set node update info for this node
28610  macro_nod_pt->set_node_update_info
28611  (new_el_pt,s_in_macro_node_update_element,
28612  geom_object_vector_pt);
28613  }
28614 
28615  } // if (!found_node_in_other_shared_boundaries ||
28616  // !found_on_haloed_element_with_other_processor)
28617 
28618  // If there are additional values, resize the node
28619  unsigned n_new_val=new_nod_pt->nvalue();
28620 
28621  // Check if necessary to state all the info. to the node if it has
28622  // been already found in shared boundaries with other processors
28623  // or in the haloed elements with of other processors with the
28624  // iproc processor
28625  if (!found_node_in_other_shared_boundaries ||
28626  !found_on_haloed_element_with_other_processor)
28627  {
28628  if (n_val>n_new_val)
28629  {
28630  // If it has been necessary to resize then it may be becuse
28631  // the node is on a FSI boundary, if that is the case we need
28632  // to set a map for these external values
28633 
28634  // Cast to a boundary node
28635  BoundaryNodeBase *bnod_pt =
28636  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28637 
28638  // Create storage, if it doesn't already exist, for the map
28639  // that will contain the position of the first entry of
28640  // this face element's additional values,
28641  if(bnod_pt->index_of_first_value_assigned_by_face_element_pt()==0)
28642  {
28643  bnod_pt->index_of_first_value_assigned_by_face_element_pt()=
28644  new std::map<unsigned, unsigned>;
28645  }
28646 
28647  // Get pointer to the map
28648  std::map<unsigned, unsigned>* map_pt=
28649  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
28650 
28651  // The id of the face to which this node belong in the bulk
28652  // element
28653  const unsigned id_face = 0;
28654  // We only resize the node values Vector if we haven't done it yet
28655  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
28656 
28657  // If this node hasn't been resized for current id
28658  if(p==map_pt->end())
28659  {
28660  // assign the face element id and the position of the
28661  //first entry to the boundary node
28662  (*map_pt)[id_face] = n_new_val;
28663 
28664  // resize the node vector of values
28665  new_nod_pt->resize(n_val);
28666  }
28667 
28668  } // if (n_val>n_new_val)
28669 
28670  } // if (!found_node_in_other_shared_boundaries ||
28671  // !found_on_haloed_element_with_other_processor)
28672 
28673  // Is the new node a SolidNode?
28674  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
28675  if (solid_nod_pt!=0)
28676  {
28677  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
28678  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
28679  {
28680  for (unsigned t=0;t<n_prev;t++)
28681  {
28682  double read_data =
28683  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28684 
28685  // Check if necessary to state all the info. to the node if
28686  // it has been already found in shared boundaries with other
28687  // processors or in the haloed elements with of other
28688  // processors with the iproc processor
28689  if (!found_node_in_other_shared_boundaries ||
28690  !found_on_haloed_element_with_other_processor)
28691  {
28692  solid_nod_pt->variable_position_pt()->
28693  set_value(t, i_val, read_data);
28694  } // if (!found_node_in_other_shared_boundaries ||
28695  // !found_on_haloed_element_with_other_processor)
28696 
28697  }
28698 
28699  }
28700 
28701 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28702  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28703  << " Number of values solid node: "
28704  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28705  << std::endl;
28706 #endif
28707  const unsigned nvalues_solid_node =
28708  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28709  Vector<double> values_solid_node(nvalues_solid_node);
28710  for (unsigned i = 0; i < nvalues_solid_node; i++)
28711  {
28712  values_solid_node[i] =
28713  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28714  }
28715 
28716  // Check if necessary to state all the info. to the node if it
28717  // has been already found in shared boundaries with other
28718  // processors or in the haloed elements with of other processors
28719  // with the iproc processor
28720  if (!found_node_in_other_shared_boundaries ||
28721  !found_on_haloed_element_with_other_processor)
28722  {
28723  unsigned index = 0;
28724  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28725  } // if (!found_node_in_other_shared_boundaries ||
28726  // !found_on_haloed_element_with_other_processor)
28727 
28728  }
28729 
28730  // Get copied history values
28731  // unsigned n_val=new_nod_pt->nvalue();
28732  for (unsigned i_val=0;i_val<n_val;i_val++)
28733  {
28734  for (unsigned t=0;t<n_prev;t++)
28735  {
28736  double read_data =
28737  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28738 
28739  // Check if necessary to state all the info. to the node if it
28740  // has been already found in shared boundaries with other
28741  // processors or in the haloed elements with of other
28742  // processors with the iproc processor
28743  if (!found_node_in_other_shared_boundaries ||
28744  !found_on_haloed_element_with_other_processor)
28745  {
28746  new_nod_pt->set_value(t, i_val, read_data);
28747  } // if (!found_node_in_other_shared_boundaries ||
28748  // !found_on_haloed_element_with_other_processor)
28749 
28750  }
28751 
28752  }
28753 
28754  // Get copied history values for positions
28755  unsigned n_dim=new_nod_pt->ndim();
28756  for (unsigned idim=0;idim<n_dim;idim++)
28757  {
28758  for (unsigned t=0;t<n_prev;t++)
28759  {
28760  double read_data =
28761  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28762 
28763  // Check if necessary to state all the info. to the node if it
28764  // has been already found in shared boundaries with other
28765  // processors or in the haloed elements with of other
28766  // processors with the iproc processor
28767  if (!found_node_in_other_shared_boundaries ||
28768  !found_on_haloed_element_with_other_processor)
28769  {
28770  // Copy to coordinate
28771  new_nod_pt->x(t,idim) = read_data;
28772 // DEBP(new_nod_pt->x(t,idim));
28773  } // if (!found_node_in_other_shared_boundaries ||
28774  // !found_on_haloed_element_with_other_processor)
28775  }
28776  }
28777 
28778  } // if (is_node_on_shared_boundary != 1)
28779 
28780  // If the node was not found in other shared boundaries (possibly
28781  // because it is the first time the node has been sent) then copy
28782  // the node to the shared boundaries where it should be, use the
28783  // special container for this cases
28784  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
28785  // shared
28786  // boundaries with
28787  // other processors
28788  !found_node_in_other_shared_boundaries) // The node has not
28789  // been previously
28790  // set as with
28791  // shared with
28792  // other processors
28793  // (first time)
28794  {
28795 
28796  // Update the node pointer in all the references of the node
28797  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
28798  other_proc_shd_bnd_node_pt,
28799  other_processor_1,
28800  other_processor_2,
28801  other_shared_boundaries,
28802  other_indexes,
28803  global_node_names,
28804  node_name_to_global_index,
28805  global_shared_node_pt);
28806 
28807  } // if (!found_node_in_other_shared_boundaries)
28808 
28809  }
28810 
28811 #endif // #ifdef OOMPH_HAS_MPI
28812 
28813  //======================================================================
28814  /// \short Get the nodes on the boundary (b), these are stored in the
28815  /// segment they belong (also used by the load balance method to
28816  /// re-set the number of segments per boundary after load balance has
28817  /// taken place)
28818  //======================================================================
28819  template <class ELEMENT>
28821  const unsigned &b, Vector<Vector<Node*> > &tmp_segment_nodes)
28822  {
28823  // Clear the data structure were to return the nodes
28824  tmp_segment_nodes.clear();
28825 
28826  // Temporary storage for face elements
28827  Vector<FiniteElement*> face_el_pt;
28828 
28829  // Temporary storage for number of elements adjacent to the boundary
28830  unsigned nel = 0;
28831 
28832  // Temporary storage for elements adjacent to the boundary that have
28833  // a common edge (related with internal boundaries)
28834  unsigned n_repeated_ele = 0;
28835 
28836  // Get the number of regions
28837  const unsigned n_regions = this->nregion();
28838 
28839  // Temporary storage for already visited pair of nodes (edges)
28840  Vector < std::pair<Node*, Node *> > done_nodes_pt;
28841 
28842  // Are there more than one region?
28843  if (n_regions > 1)
28844  {
28845  for (unsigned rr = 0 ; rr < n_regions; rr++)
28846  {
28847  const unsigned region_id =
28848  static_cast<unsigned>(this->Region_attribute[rr]);
28849 
28850  // Loop over all elements on boundaries in region rr
28851  const unsigned nel_in_region =
28852  this->nboundary_element_in_region(b, region_id);
28853 
28854  // Number of repeated element in region
28855  unsigned nel_repeated_in_region = 0;
28856 
28857  // Only bother to do anything else, if there are elements
28858  // associated with the boundary and the current region
28859  if (nel_in_region > 0)
28860  {
28861  // Flag that activates when a repeated face element is found,
28862  // possibly because we are dealing with an internal boundary
28863  bool repeated = false;
28864 
28865  // Loop over the bulk elements adjacent to boundary b
28866  for (unsigned e = 0; e < nel_in_region; e++)
28867  {
28868  // Get pointer to the bulk element that is adjacent to boundary b
28869  FiniteElement* bulk_elem_pt =
28870  this->boundary_element_in_region_pt(b, region_id, e);
28871 
28872 #ifdef OOMPH_HAS_MPI
28873  // In a distributed mesh only work with nonhalo elements
28874  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28875  {
28876  // Increase the number of repeated elements
28877  n_repeated_ele++;
28878  // Go for the next element
28879  continue;
28880  }
28881 #endif
28882 
28883  //Find the index of the face of element e along boundary b
28884  int face_index =
28885  this->face_index_at_boundary_in_region(b, region_id, e);
28886 
28887  // Before adding the new element we need to be sure that the
28888  // edge that this element represents has not been already
28889  // added
28890  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28891  bulk_elem_pt, face_index);
28892 
28893  // Number of nodes in the face element
28894  const unsigned n_nodes = tmp_ele_pt->nnode();
28895 
28896  std::pair<Node*, Node*> tmp_pair =
28897  std::make_pair(tmp_ele_pt->node_pt(0),
28898  tmp_ele_pt->node_pt(n_nodes - 1));
28899 
28900  std::pair<Node*, Node*> tmp_pair_inverse =
28901  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28902  tmp_ele_pt->node_pt(0));
28903 
28904  // Search for repeated nodes
28905  unsigned n_done_nodes = done_nodes_pt.size();
28906  for (unsigned l = 0; l < n_done_nodes; l++)
28907  {
28908  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
28909  == done_nodes_pt[l])
28910  {
28911  nel_repeated_in_region++;
28912  repeated = true;
28913  break;
28914  }
28915 
28916  } // for (l < n_done_nodes)
28917 
28918  // Create new face element?
28919  if (!repeated)
28920  {
28921  // Add the pair of nodes (edge) to the node dones
28922  done_nodes_pt.push_back(tmp_pair);
28923  // Add the face element to the storage
28924  face_el_pt.push_back(tmp_ele_pt);
28925  }
28926  else
28927  {
28928  // Clean up
28929  delete tmp_ele_pt;
28930  tmp_ele_pt = 0;
28931  }
28932 
28933  // Re-start
28934  repeated = false;
28935 
28936  } // for (e < nel_in_region)
28937 
28938  // Add on the number of elements in the boundary with the
28939  // current region
28940  nel += nel_in_region;
28941 
28942  // Add on the number of repeated elements
28943  n_repeated_ele += nel_repeated_in_region;
28944 
28945  } // if (nel_in_region > 0)
28946 
28947  } // for (rr < n_regions)
28948 
28949  } // if (n_regions > 1)
28950  //Otherwise it's just the normal boundary functions
28951  else
28952  {
28953  // Assign the number of boundary elements
28954  nel = this->nboundary_element(b);
28955 
28956  //Only bother to do anything else, if there are elements
28957  if (nel > 0)
28958  {
28959  // Flag that activates when a repeated face element is found,
28960  // possibly because we are dealing with an internal boundary
28961  bool repeated = false;
28962 
28963  // Loop over the bulk elements adjacent to boundary b
28964  for (unsigned e = 0; e < nel; e++)
28965  {
28966  // Get pointer to the bulk element that is adjacent to boundary b
28967  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
28968 
28969 #ifdef OOMPH_HAS_MPI
28970  // In a distributed mesh only work with nonhalo elements
28971  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28972  {
28973  // Increase the number of repeated elements
28974  n_repeated_ele++;
28975  // Go for the next element
28976  continue;
28977  }
28978 #endif
28979 
28980  //Find the index of the face of element e along boundary b
28981  int face_index = this->face_index_at_boundary(b, e);
28982 
28983  // Before adding the new element we need to be sure that the
28984  // edge that this element represent has not been already added
28985  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28986  bulk_elem_pt, face_index);
28987 
28988  // Number of nodes in the face element
28989  const unsigned n_nodes = tmp_ele_pt->nnode();
28990 
28991  std::pair<Node*, Node*> tmp_pair =
28992  std::make_pair(tmp_ele_pt->node_pt(0),
28993  tmp_ele_pt->node_pt(n_nodes - 1));
28994 
28995  std::pair<Node*, Node*> tmp_pair_inverse =
28996  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28997  tmp_ele_pt->node_pt(0));
28998 
28999  // Search for repeated nodes
29000  unsigned n_done_nodes = done_nodes_pt.size();
29001  for (unsigned l = 0; l < n_done_nodes; l++)
29002  {
29003  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
29004  == done_nodes_pt[l])
29005  {
29006  n_repeated_ele++;
29007  repeated = true;
29008  break;
29009  }
29010 
29011  } // for (l < n_done_nodes)
29012 
29013  // Create new face element
29014  if (!repeated)
29015  {
29016  // Add the pair of nodes (edge) to the node dones
29017  done_nodes_pt.push_back(tmp_pair);
29018  // Add the face element to the storage
29019  face_el_pt.push_back(tmp_ele_pt);
29020  }
29021  else
29022  {
29023  // Free the repeated bulk element!!
29024  delete tmp_ele_pt;
29025  tmp_ele_pt = 0;
29026  }
29027 
29028  // Re-start
29029  repeated = false;
29030 
29031  } // for (e < nel)
29032 
29033  } // if (nel > 0)
29034 
29035  } // else if (n_regions > 1)
29036 
29037  // Substract the repeated elements
29038  nel -= n_repeated_ele;
29039 
29040 #ifdef PARANOID
29041  if (nel!=face_el_pt.size())
29042  {
29043  std::ostringstream error_message;
29044  error_message
29045  << "The independet counting of face elements ("<<nel<<") for "
29046  << "boundary ("<<b<<") is different\n"
29047  << "from the real number of face elements in the container ("
29048  << face_el_pt.size() <<")\n";
29049  throw OomphLibError(error_message.str(),
29050  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29051  OOMPH_EXCEPTION_LOCATION);
29052  }
29053 #endif
29054 
29055  //Only bother to do anything else, if there are elements
29056  if (nel > 0)
29057  {
29058  // Assign the number of nonhalo face elements
29059  const unsigned nnon_halo_face_elements = nel;
29060 
29061  // The vector of list to store the "segments" that compound the
29062  // boundary (segments may appear only in a distributed mesh)
29063  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
29064 
29065  // Number of already sorted face elements (only nonhalo face
29066  // elements for a distributed mesh)
29067  unsigned nsorted_face_elements = 0;
29068 
29069  // Keep track of who's done (in a distributed mesh this apply to
29070  // nonhalo only)
29071  std::map<FiniteElement*, bool> done_ele;
29072 
29073  // Keep track of which element is inverted (in distributed mesh
29074  // the elements may be inverted with respect to the segment they
29075  // belong)
29076  std::map<FiniteElement*, bool> is_inverted;
29077 
29078  // Iterate until all possible segments have been created. In a non
29079  // distributed mesh there is only one segment which defines the
29080  // complete boundary
29081  while(nsorted_face_elements < nnon_halo_face_elements)
29082  {
29083  // The ordered list of face elements (in a distributed mesh a
29084  // collection of continuous face elements define a segment)
29085  std::list<FiniteElement*> sorted_el_pt;
29086 
29087 #ifdef PARANOID
29088  // Select an initial element for the segment
29089  bool found_initial_face_element = false;
29090 #endif
29091 
29092  FiniteElement* ele_face_pt = 0;
29093 
29094  unsigned iface = 0;
29095 #ifdef OOMPH_HAS_MPI
29096  if (this->is_mesh_distributed())
29097  {
29098  for (iface = 0; iface < nel; iface++)
29099  {
29100  ele_face_pt = face_el_pt[iface];
29101  // If not done then take it as initial face element
29102  if (!done_ele[ele_face_pt])
29103  {
29104 #ifdef PARANOID
29105  // Set the flag to indicate the initial element was
29106  // found
29107  found_initial_face_element = true;
29108 #endif
29109  // Increase the number of sorted face elements
29110  nsorted_face_elements++;
29111  // Set the index to the next face element
29112  iface++;
29113  // Add the face element in the container
29114  sorted_el_pt.push_back(ele_face_pt);
29115  // Mark as done
29116  done_ele[ele_face_pt] = true;
29117  break;
29118  } // if (!done_el[ele_face_pt])
29119  } // for (iface < nel)
29120  } // if (this->is_mesh_distributed())
29121  else
29122  {
29123 #endif // #ifdef OOMPH_HAS_MPI
29124 
29125  // When the mesh is not distributed just take the first
29126  // element and put it in the ordered list
29127  ele_face_pt = face_el_pt[0];
29128 #ifdef PARANOID
29129  // Set the flag to indicate the initial element was found
29130  found_initial_face_element = true;
29131 #endif
29132  // Increase the number of sorted face elements
29133  nsorted_face_elements++;
29134  // Set the index to the next face element
29135  iface = 1;
29136  // Add the face element in the container
29137  sorted_el_pt.push_back(ele_face_pt);
29138  // Mark as done
29139  done_ele[ele_face_pt] = true;
29140 #ifdef OOMPH_HAS_MPI
29141  } // else if (this->is_mesh_distributed())
29142 #endif
29143 
29144 #ifdef PARANOID
29145  if (!found_initial_face_element)
29146  {
29147  std::ostringstream error_message;
29148  error_message
29149  <<"Could not find an initial face element for the current segment\n";
29150  throw OomphLibError(error_message.str(),
29151  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29152  OOMPH_EXCEPTION_LOCATION);
29153  }
29154 #endif
29155 
29156  // Number of nodes in the face element
29157  const unsigned nnod = ele_face_pt->nnode();
29158 
29159  // Left and rightmost nodes (the left and right nodes of the
29160  // current face element)
29161  Node* left_node_pt = ele_face_pt->node_pt(0);
29162  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29163 
29164  // Continue iterating if a new face element has been added to
29165  // the list
29166  bool face_element_added = false;
29167 
29168  // While a new face element has been added to the set of sorted
29169  // face elements continue iterating
29170  do
29171  {
29172  // Start from the next face element since we have already
29173  // added the previous one as the initial face element (any
29174  // previous face element had to be added on previous
29175  // iterations)
29176  for (unsigned iiface=iface;iiface<nel;iiface++)
29177  {
29178  // Re-start flag
29179  face_element_added = false;
29180 
29181  // Get the candidate element
29182  ele_face_pt = face_el_pt[iiface];
29183 
29184  // Check that the candidate element has not been done and is
29185  // not a halo element
29186  if (!done_ele[ele_face_pt])
29187  {
29188  // Get the left and right nodes of the current element
29189  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29190  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29191 
29192  // New element fits at the left of segment and is not inverted
29193  if (left_node_pt == local_right_node_pt)
29194  {
29195  left_node_pt = local_left_node_pt;
29196  sorted_el_pt.push_front(ele_face_pt);
29197  is_inverted[ele_face_pt] = false;
29198  face_element_added = true;
29199  }
29200  // New element fits at the left of segment and is inverted
29201  else if (left_node_pt == local_left_node_pt)
29202  {
29203  left_node_pt = local_right_node_pt;
29204  sorted_el_pt.push_front(ele_face_pt);
29205  is_inverted[ele_face_pt] = true;
29206  face_element_added = true;
29207  }
29208  // New element fits on the right of segment and is not inverted
29209  else if (right_node_pt == local_left_node_pt)
29210  {
29211  right_node_pt = local_right_node_pt;
29212  sorted_el_pt.push_back(ele_face_pt);
29213  is_inverted[ele_face_pt] = false;
29214  face_element_added = true;
29215  }
29216  // New element fits on the right of segment and is inverted
29217  else if (right_node_pt == local_right_node_pt)
29218  {
29219  right_node_pt = local_left_node_pt;
29220  sorted_el_pt.push_back(ele_face_pt);
29221  is_inverted[ele_face_pt] = true;
29222  face_element_added = true;
29223  }
29224 
29225  if (face_element_added)
29226  {
29227  // Mark the face element as done
29228  done_ele[ele_face_pt] = true;
29229  nsorted_face_elements++;
29230  break;
29231  }
29232 
29233  } // if (!done_el[ele_face_pt])
29234 
29235  } // for (iiface<nnon_halo_face_element)
29236 
29237  }while(face_element_added &&
29238  (nsorted_face_elements < nnon_halo_face_elements));
29239 
29240  // Store the created segment in the vector of segments
29241  segment_sorted_ele_pt.push_back(sorted_el_pt);
29242 
29243  } // while(nsorted_face_elements < nnon_halo_face_elements);
29244 
29245  // The number of boundary segments in this processor
29246  const unsigned nsegments = segment_sorted_ele_pt.size();
29247 
29248 #ifdef PARANOID
29249  if (nnon_halo_face_elements > 0 && nsegments == 0)
29250  {
29251  std::ostringstream error_message;
29252  error_message
29253  << "The number of segments is zero, but the number of nonhalo\n"
29254  << "elements is: (" << nnon_halo_face_elements << ")\n";
29255  throw OomphLibError(error_message.str(),
29256  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29257  OOMPH_EXCEPTION_LOCATION);
29258  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29259 #endif
29260 
29261  // Go through all the segments, visit each face element in order
29262  // and get the nodes based that represent the boundary segment
29263 
29264  // Resize the container to store the nodes with the required
29265  // number of segments
29266  tmp_segment_nodes.resize(nsegments);
29267 
29268  for (unsigned is = 0; is < nsegments; is++)
29269  {
29270 #ifdef PARANOID
29271  if (segment_sorted_ele_pt[is].size() == 0)
29272  {
29273  std::ostringstream error_message;
29274  error_message
29275  << "The (" << is << ")-th segment has no elements\n";
29276  throw OomphLibError(error_message.str(),
29277  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29278  OOMPH_EXCEPTION_LOCATION);
29279  } // if (segment_sorted_ele_pt[is].size() == 0)
29280 #endif
29281 
29282  // Get access to the first element on the segment
29283  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29284 
29285  // Number of nodes
29286  const unsigned nnod = first_ele_pt->nnode();
29287 
29288  // Get the first node of the current segment
29289  Node *first_node_pt = first_ele_pt->node_pt(0);
29290  if (is_inverted[first_ele_pt])
29291  {
29292  first_node_pt = first_ele_pt->node_pt(nnod-1);
29293  }
29294 
29295  // Add the node to the corresponding segment
29296  tmp_segment_nodes[is].push_back(first_node_pt);
29297 
29298  // Now loop over face elements in order to get the nodes
29299  for (std::list<FiniteElement*>::iterator it =
29300  segment_sorted_ele_pt[is].begin();
29301  it != segment_sorted_ele_pt[is].end(); it++)
29302  {
29303  // Get element
29304  FiniteElement* ele_pt = *it;
29305 
29306  // The last node pointer
29307  Node* last_node_pt = 0;
29308 
29309  // Get the last node
29310  if (!is_inverted[ele_pt])
29311  {
29312  last_node_pt = ele_pt->node_pt(nnod-1);
29313  }
29314  else
29315  {
29316  last_node_pt = ele_pt->node_pt(0);
29317  }
29318 
29319  // Add the node to the corresponding segment
29320  tmp_segment_nodes[is].push_back(last_node_pt);
29321 
29322  } // iterator over the elements in the segment
29323 
29324  } // for (is < nsegments)
29325 
29326  } // for (if (nel > 0))
29327 
29328  // Free memory allocation
29329  for (unsigned e = 0; e < nel; e++)
29330  {
29331  delete face_el_pt[e];
29332  face_el_pt[e] = 0;
29333  } // for (e < nel)
29334 
29335  }
29336 
29337 //======================================================================
29338 /// Adapt problem based on specified elemental error estimates
29339 /// This function implement serial and parallel mesh adaptation, the
29340 /// sections for parallel mesh adaptation are clearly identified by
29341 /// checking whether the mesh is distributed or not
29342 //======================================================================
29343  template <class ELEMENT>
29345  const Vector<double>& elem_error)
29346  {
29347  double t_start_overall=TimingHelpers::timer();
29348 
29349  // ==============================================================
29350  // BEGIN: Compute target areas
29351  // ==============================================================
29352 
29353  // Get refinement targets
29354  Vector<double> target_area(elem_error.size());
29355  double min_angle=compute_area_target(elem_error,
29356  target_area);
29357 
29358  // Post-process to allow only quantised target areas
29359  // in an attempt to more closely mimick the structured
29360  // case and limit the diffusion of small elements.
29361  bool quantised_areas=true;
29362  if (quantised_areas)
29363  {
29364  unsigned n=target_area.size();
29365  double total_area=0;
29366  // If the mesh is distributed then we need to get the contribution
29367  // of all processors to compute the total areas
29368  // ------------------------------------------
29369  // DISTRIBUTED MESH: BEGIN
29370  // ------------------------------------------
29371 #ifdef OOMPH_HAS_MPI
29372  if (this->is_mesh_distributed())
29373  {
29374  // When working in parallel we get the total area from the sum
29375  // of the the sub-areas of all the meshes
29376  double sub_area = 0.0;
29377 
29378  // Only add the area of nonhalo elements
29379  for (unsigned e=0;e<n;e++)
29380  {
29381  // Get the pointer to the element
29382  FiniteElement* ele_pt = this->finite_element_pt(e);
29383  if (!ele_pt->is_halo())
29384  {
29385  sub_area+=ele_pt->size();
29386  }
29387  } // for (e<n)
29388 
29389  // Get the communicator of the mesh
29390  OomphCommunicator* comm_pt = this->communicator_pt();
29391 
29392  // Get the total area
29393  MPI_Allreduce(&sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM,
29394  comm_pt->mpi_comm());
29395  }
29396  else
29397  {
29398  for (unsigned e=0;e<n;e++)
29399  {
29400  total_area+=this->finite_element_pt(e)->size();
29401  }
29402  }
29403  // ------------------------------------------
29404  // DISTRIBUTED MESH: END
29405  // ------------------------------------------
29406 #else // #ifdef OOMPH_HAS_MPI
29407  for (unsigned e=0;e<n;e++)
29408  {
29409  total_area+=this->finite_element_pt(e)->size();
29410  }
29411 #endif // #ifdef OOMPH_HAS_MPI
29412 
29413  for (unsigned e=0;e<n;e++)
29414  {
29415  unsigned level=
29416  unsigned(ceil(log(target_area[e]/total_area)/log(1.0/3.0)))-1;
29417  double new_target_area=total_area*pow(1.0/3.0,int(level));
29418  target_area[e]=new_target_area;
29419  }
29420 
29421  }
29422 
29423  // std::ofstream tmp;
29424  // tmp.open((Global_string_for_annotation:: String[0]+"overall_target_areas"+
29425  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29426 
29427  // Get maximum target area
29428  unsigned n=target_area.size();
29429  double max_area=0.0;
29430  double min_area=DBL_MAX;
29431  for (unsigned e=0;e<n;e++)
29432  {
29433  if (target_area[e]>max_area) max_area=target_area[e];
29434  if (target_area[e]<min_area) min_area=target_area[e];
29435 
29436  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29437  // finite_element_pt(e)->node_pt(1)->x(0)+
29438  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29439  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29440  // finite_element_pt(e)->node_pt(1)->x(1)+
29441  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29442  // << target_area[e] << " "
29443  // << finite_element_pt(e)->size() << " "
29444  // << elem_error[e] << " " << std::endl;
29445  }
29446 
29447  //tmp.close();
29448 
29449  oomph_info << "Maximum target area: " << max_area << std::endl;
29450  oomph_info << "Minimum target area: " << min_area << std::endl;
29451  oomph_info << "Number of elements to be refined: "
29452  << this->Nrefined << std::endl;
29453  oomph_info << "Number of elements to be unrefined: "
29454  << this->Nunrefined << std::endl;
29455  oomph_info << "Min. angle: " << min_angle << std::endl;
29456 
29457  double orig_max_area, orig_min_area;
29458  this->max_and_min_element_size(orig_max_area, orig_min_area);
29459  oomph_info << "Max./min. element size in original mesh: "
29460  << orig_max_area << " "
29461  << orig_min_area << std::endl;
29462 
29463  // ==============================================================
29464  // END: Compute target areas
29465  // ==============================================================
29466 
29467  // Check if boundaries need to be updated (regardless of
29468  // requirements of bulk error estimator) but don't do anything!
29469  bool check_only=true;
29470  bool outer_boundary_update_necessary= false;
29471  bool inner_boundary_update_necessary= false;
29472  bool inner_open_boundary_update_necessary=false;
29473 
29474  // Get the number of outer boundaries and check if they require
29475  // update
29476  const unsigned nouter=this->Outer_boundary_pt.size();
29477 
29478  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29479  {
29480  // loop over the outer boundaries
29481  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29482  {
29483  outer_boundary_update_necessary=
29484  this->update_polygon_using_face_mesh(this->Outer_boundary_pt[i_outer],
29485  check_only);
29486  // Break the loop if at least one needs updating
29487  if (outer_boundary_update_necessary) break;
29488  }
29489 
29490  // Do not waste time if we already know that it is necessary an update
29491  // on the boundary representation
29492  if (!outer_boundary_update_necessary)
29493  {
29494  // Check if we need to generate a new 1D mesh representation of
29495  // the inner hole boundaries
29496  const unsigned nhole=this->Internal_polygon_pt.size();
29497  Vector<Vector<double> > internal_point_coord(nhole);
29498  inner_boundary_update_necessary=
29499  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29500  check_only);
29501 
29502  // If there was not necessary a change even on the internal closed
29503  // curve then finally check for the open curves as well
29504  if (!inner_boundary_update_necessary)
29505  {
29506  const unsigned n_open_polyline =
29507  this->Internal_open_curve_pt.size();
29508  // loop over the open polylines
29509  for (unsigned i = 0; i < n_open_polyline; i++)
29510  {
29511  inner_open_boundary_update_necessary=
29512  this->update_open_curve_using_face_mesh(
29513  this->Internal_open_curve_pt[i], check_only);
29514  // If at least one needs modification then break the for loop
29515  if (inner_open_boundary_update_necessary) break;
29516  }
29517  }
29518  }
29519  }
29520 
29521  // Flag to indicate whether we need to adapt or not (for parallel
29522  // mesh adaptation only)
29523  int adapt_all = 0;
29524  // ------------------------------------------
29525  // DISTRIBUTED MESH: BEGIN
29526  // ------------------------------------------
29527 #ifdef OOMPH_HAS_MPI
29528  // When working in distributed meshes we need to ensure that all the
29529  // processors take part on the adaptation process. If at least one
29530  // of the processors requires adaptation then all processor take
29531  // part on the adaptation process.
29532  int adapt_this_processor = 0;
29533  if (this->is_mesh_distributed())
29534  {
29535  // Do this processor requires adaptation?
29536  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29537  (min_angle < min_permitted_angle())
29538  || (outer_boundary_update_necessary)
29539  || (inner_boundary_update_necessary)
29540  || (inner_open_boundary_update_necessary) )
29541  {adapt_this_processor = 1;}
29542 
29543  // Get the communicator of the mesh
29544  OomphCommunicator* comm_pt = this->communicator_pt();
29545 
29546  // Verify if at least one processor needs mesh adaptation
29547  MPI_Allreduce(&adapt_this_processor, &adapt_all, 1, MPI_INT, MPI_SUM,
29548  comm_pt->mpi_comm());
29549  }
29550 #endif
29551  // ------------------------------------------
29552  // DISTRIBUTED MESH: END
29553  // ------------------------------------------
29554 
29555  // Should we bother to adapt?
29556  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29557  (min_angle < min_permitted_angle()) || (outer_boundary_update_necessary)
29558  || (inner_boundary_update_necessary)
29559  || (inner_open_boundary_update_necessary) || (adapt_all) )
29560  {
29561  if (! ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ) )
29562  {
29563 
29564  if ( (outer_boundary_update_necessary)
29565  || (inner_boundary_update_necessary)
29566  || (inner_open_boundary_update_necessary) )
29567  {
29568  oomph_info
29569  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29570  << "representation; setting Nrefined to number of elements.\n"
29571  << "outer_boundary_update_necessary : "
29572  << outer_boundary_update_necessary << "\n"
29573  << "inner_boundary_update_necessary : "
29574  << inner_boundary_update_necessary << "\n"
29575  << "inner_open_boundary_update_necessary: "
29576  << inner_open_boundary_update_necessary << "\n";
29577  Nrefined=nelement();
29578  }
29579  else
29580  {
29581  oomph_info
29582  << "Mesh regeneration triggered by min angle criterion;\n"
29583  << "setting Nrefined to number of elements.\n";
29584  Nrefined=nelement();
29585  }
29586  }
29587 
29588  // ------------------------------------------
29589  // DISTRIBUTED MESH: BEGIN
29590  // ------------------------------------------
29591 #ifdef OOMPH_HAS_MPI
29592  else if (this->is_mesh_distributed() &&
29593  adapt_this_processor == 0 && adapt_all > 0)
29594  {
29595  oomph_info
29596  << "Mesh regeneration triggered by (" << adapt_all << ") processor(s) "
29597  << "that require(s)\n adaptation\n";
29598  }
29599 #endif
29600  // ------------------------------------------
29601  // DISTRIBUTED MESH: END
29602  // ------------------------------------------
29603 
29604  // ==============================================================
29605  // BEGIN: Updating of boundaries representation (unrefinement and
29606  // refinement of polylines)
29607  // ==============================================================
29608 
29609  // Add the initial and final vertices of the polylines that
29610  // present connections to a list of non-delete-able vertices. The
29611  // vertices where the connections are performed cannot be deleted
29612  add_vertices_for_non_deletion();
29613 
29614  // ------------------------------------------
29615  // DISTRIBUTED MESH: BEGIN
29616  // ------------------------------------------
29617 #ifdef OOMPH_HAS_MPI
29618  // Synchronise connections for shared boundaries among
29619  // processors. This is required since one of the processor may noy
29620  // know that some of its shared boundaries have connections, thus
29621  // the vertices receiving the connections cannot be deleted
29622  if (this->is_mesh_distributed())
29623  {
29624  synchronize_shared_boundary_connections();
29625  }
29626 #endif // #ifdef OOMPH_HAS_MPI
29627  // ------------------------------------------
29628  // DISTRIBUTED MESH: END
29629  // ------------------------------------------
29630 
29631  // Are we allowing automatic insertion of vertices on boundaries?
29632  // If YES then Triangle automatically insert points along
29633  // boundaries, if NOT, then points are inserted along the
29634  // boundaries based on the target areas of boundary elements. When
29635  // the mesh is distributed the automatic insertion of vertices by
29636  // Triangle along the boundaries is not allowed
29637  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29638  {
29639  //Generate a new 1D mesh representation of the inner hole boundaries
29640  unsigned nhole=this->Internal_polygon_pt.size();
29641  Vector<Vector<double> > internal_point_coord(nhole);
29642  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29643 
29644  //Update the representation of the outer boundary
29645  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29646  {
29647  this->update_polygon_using_face_mesh(
29648  this->Outer_boundary_pt[i_outer]);
29649  }
29650 
29651  // After updating outer and internal closed boundaries it is also
29652  // necessary to update internal boundaries.
29653  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29654  for (unsigned i = 0; i < n_open_polyline; i++)
29655  {
29656  this->update_open_curve_using_face_mesh(
29657  this->Internal_open_curve_pt[i]);
29658  }
29659 
29660  }
29661  else
29662  {
29663  // Update the representation of the internal boundaries using
29664  // the element's target area
29665 
29666  // Get the number of interal polygons
29667  const unsigned ninternal=this->Internal_polygon_pt.size();
29668  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29669  {
29670  this->update_polygon_using_elements_area(
29671  this->Internal_polygon_pt[i_internal], target_area);
29672  }
29673 
29674  // Update the representation of the outer boundaries using the
29675  // element's target area
29676  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29677  {
29678  this->update_polygon_using_elements_area(
29679  this->Outer_boundary_pt[i_outer], target_area);
29680  }
29681 
29682  // Update the representation of the internal open boundaries
29683  // using the element's target areas
29684  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29685  for (unsigned i = 0; i < n_open_polyline; i++)
29686  {
29687  this->update_open_curve_using_elements_area(
29688  this->Internal_open_curve_pt[i], target_area);
29689  }
29690 
29691  // ------------------------------------------
29692  // DISTRIBUTED MESH: BEGIN
29693  // ------------------------------------------
29694 
29695  // When working with a distributed mesh we require to update the
29696  // boundary representation of the shared boundaries, this is
29697  // based on the target areas of the elements adjaced to the
29698  // shared boundaries
29699 #ifdef OOMPH_HAS_MPI
29700  // Update shared boundaries if the mesh is distributed
29701  if (this->is_mesh_distributed())
29702  {
29703  // Get the rank of the current processor
29704  const unsigned my_rank = this->communicator_pt()->my_rank();
29705 
29706  // Get the number of shared curves
29707  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29708  // Loop over the shared curves in the current processor
29709  for (unsigned nc = 0; nc < n_curves; nc ++)
29710  {
29711  // Update the shared polyline
29712  this->update_shared_curve_using_elements_area(
29713  this->Shared_boundary_polyline_pt[my_rank][nc],//shared_curve,
29714  target_area);
29715  }
29716 
29717  } // if (this->is_mesh_distributed())
29718 #endif
29719 
29720  // ------------------------------------------
29721  // DISTRIBUTED MESH: END
29722  // ------------------------------------------
29723 
29724  } // else if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29725 
29726  // ==============================================================
29727  // END: Updating of boundaries representation (unrefinement and
29728  // refinement of polylines)
29729  // ==============================================================
29730 
29731  // ==============================================================
29732  // BEGIN: Reset boundary coordinates for boundaries with no
29733  // associated GeomObject
29734  // ==============================================================
29735 
29736  //If there is not a geometric object associated with the boundary
29737  //then reset the boundary coordinates so that the lengths are
29738  //consistent in the new mesh and the old mesh.
29739  const unsigned n_boundary = this->nboundary();
29740 
29741  const double t_start_first_stage_segments_connectivity =
29742  TimingHelpers::timer();
29743 
29744  // ------------------------------------------
29745  // DISTRIBUTED MESH: BEGIN
29746  // ------------------------------------------
29747 #ifdef OOMPH_HAS_MPI
29748  // Clear storage for assignment of initial zeta values for
29749  // boundaries
29750  if (this->is_mesh_distributed())
29751  {
29752  this->Assigned_segments_initial_zeta_values.clear();
29753  }
29754 #endif // #ifdef OOMPH_HAS_MPI
29755  // ------------------------------------------
29756  // DISTRIBUTED MESH: END
29757  // ------------------------------------------
29758 
29759  // Loop over the boundaries to assign boundary coordinates
29760  for(unsigned b=0;b<n_boundary;++b)
29761  {
29762  // ------------------------------------------
29763  // DISTRIBUTED MESH: BEGIN
29764  // ------------------------------------------
29765 #ifdef OOMPH_HAS_MPI
29766  if (this->is_mesh_distributed())
29767  {
29768  // In a distributed mesh, the boundaries may have been split
29769  // across processors during the distribution process, thus we
29770  // need to compute the connectivity among the segments of the
29771  // boundary to correctly assign its boundary coordinates
29772  this->
29773  compute_boundary_segments_connectivity_and_initial_zeta_values(b);
29774  }
29775 #endif
29776  // ------------------------------------------
29777  // DISTRIBUTED MESH: END
29778  // ------------------------------------------
29779 
29780  // Does the boundary has an associated GeomObject
29781  if(this->boundary_geom_object_pt(b)==0)
29782  {
29783  this->template setup_boundary_coordinates<ELEMENT>(b);
29784  }
29785 
29786  // ------------------------------------------
29787  // DISTRIBUTED MESH: BEGIN
29788  // ------------------------------------------
29789 #ifdef OOMPH_HAS_MPI
29790  if (this->is_mesh_distributed())
29791  {
29792  // Synchronise boundary coordinates for internal open curves,
29793  // also establish the boundary coordinates for the nodes on
29794  // the corners of elements not on the boundary
29795  this->synchronize_boundary_coordinates(b);
29796  }
29797 #endif
29798  // ------------------------------------------
29799  // DISTRIBUTED MESH: END
29800  // ------------------------------------------
29801 
29802  } // for (b<n_boundary)
29803 
29804  const double t_total_first_stage_segments_connectivity =
29805  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
29806 
29807  // ==============================================================
29808  // END: Reset boundary coordinates for boundaries with no
29809  // associated GeomObject
29810  // ==============================================================
29811 
29812  // ------------------------------------------
29813  // DISTRIBUTED MESH: BEGIN
29814  // ------------------------------------------
29815 #ifdef OOMPH_HAS_MPI
29816  // ==============================================================
29817  // BEGIN: Create the new representation of the domain by joining
29818  // the original boundaries and the shared boundaries.
29819  // ==============================================================
29820 
29821  // Storage for the new temporary polygons "closed" by the shared
29822  // boundaries
29823  Vector<TriangleMeshPolygon *> tmp_outer_polygons_pt;
29824 
29825  // Storage for the new temporary open curves, could be the
29826  // original open curves or "chunks" of the original open curves
29827  // not overlapped by shared boundaries
29828  Vector<TriangleMeshOpenCurve *> tmp_open_curves_pt;
29829 
29830  if (this->is_mesh_distributed())
29831  {
29832  // Create the new polygons and open curves with help of the
29833  // original polylines and shared polylines
29834  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
29835  tmp_open_curves_pt);
29836 
29837  // Create the connections of the temporary domain representations
29838  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
29839  tmp_open_curves_pt);
29840  }
29841  // ==============================================================
29842  // END: Create the new representation of the domain by joining
29843  // the original boundaries and the shared boundaries.
29844  // ==============================================================
29845 #endif
29846  // ------------------------------------------
29847  // DISTRIBUTED MESH: END
29848  // ------------------------------------------
29849 
29850  // Re-establish polylines' connections. The boundary
29851  // representation has changed (new polylines), therefore we need
29852  // to update the connection information
29853  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
29854  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
29855  restore_boundary_connections(resume_initial_connection_polyline_pt,
29856  resume_final_connection_polyline_pt);
29857 
29858  // Update the region information by setting the coordinates from the
29859  // centroid of the first element in each region (which should allow
29860  // automatic updates when the regions deform)
29861  {
29862  unsigned n_region = this->nregion();
29863  if(n_region > 1)
29864  {
29865  for(std::map<unsigned, Vector<double> >::iterator it =
29866  this->Regions_coordinates.begin();
29867  it!=this->Regions_coordinates.end(); ++it)
29868  {
29869  //Storage for the approximate centroid
29870  Vector<double> centroid(2,0.0);
29871 
29872  //Get the region id
29873  unsigned region_id = it->first;
29874 
29875  //Report information
29876  oomph_info << "Region " << region_id << ": "
29877  << it->second[0] << " " << it->second[1] << " ";
29878 
29879  //Check that there is at least one element in the region
29880  unsigned n_region_element = this->nregion_element(region_id);
29881  if(n_region_element > 0)
29882  {
29883  //Cache pointer to the first element
29884  FiniteElement* const elem_pt = this->region_element_pt(region_id,0);
29885 
29886  //Loop over the corners of the triangle and average
29887  for(unsigned n=0;n<3;n++)
29888  {
29889  Node* const nod_pt = elem_pt->node_pt(n);
29890  for(unsigned i=0;i<2;i++) {centroid[i] += nod_pt->x(i);}
29891  }
29892  for(unsigned i=0;i<2;i++) {centroid[i] /= 3;}
29893  //Now we have the centroid set it
29894  it->second = centroid;
29895 
29896  oomph_info << " , " <<
29897  it->second[0] << " " << it->second[1] << std::endl;
29898  } //end of case when there is at least one element
29899 
29900  } // loop over regions coordinates
29901 
29902  } // if(n_region > 1)
29903 
29904  } // Updating region info.
29905 
29906  // ==============================================================
29907  // BEGIN: Create background mesh
29908  // ==============================================================
29909 
29910  // Are we dealing with a solid mesh?
29911  SolidMesh* solid_mesh_pt=dynamic_cast<SolidMesh*>(this);
29912 
29913  // Build temporary uniform background mesh
29914  //----------------------------------------
29915  // with area set by maximum required area
29916  //---------------------------------------
29917  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt=0;
29918 
29919  // The storage for the new temporary boundaries representation to
29920  // create the background mesh
29921  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
29922  Vector<TriangleMeshClosedCurve*> hole_pt;
29923  Vector<TriangleMeshOpenCurve*> open_curves_pt;
29924 
29925 #ifdef OOMPH_HAS_MPI
29926  if (!this->is_mesh_distributed())
29927 #endif
29928  {
29929  // Copy the outer boundaries
29930  closed_curve_pt.resize(nouter);
29931  for (unsigned i = 0; i < nouter; i++)
29932  {
29933  closed_curve_pt[i] = this->Outer_boundary_pt[i];
29934  }
29935 
29936  // Copy the internal closed boundaries (may be holes)
29937  const unsigned n_holes = this->Internal_polygon_pt.size();
29938  hole_pt.resize(n_holes);
29939  for (unsigned i = 0; i < n_holes; i++)
29940  {
29941  hole_pt[i] = this->Internal_polygon_pt[i];
29942  }
29943 
29944  // Copy the internal open curves
29945  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
29946  open_curves_pt.resize(n_open_curves);
29947  for (unsigned i = 0; i < n_open_curves; i++)
29948  {
29949  open_curves_pt[i] = this->Internal_open_curve_pt[i];
29950  }
29951  }
29952  // ------------------------------------------
29953  // DISTRIBUTED MESH: BEGIN
29954  // ------------------------------------------
29955 #ifdef OOMPH_HAS_MPI
29956  else
29957  {
29958  // Copy the new representation of the outer/internal closed
29959  // boundaries
29960  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
29961  closed_curve_pt.resize(n_tmp_outer);
29962  for (unsigned i = 0; i < n_tmp_outer; i++)
29963  {
29964  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
29965  }
29966 
29967  // Copy the new representation of the internal open curves
29968  const unsigned n_open_curves = tmp_open_curves_pt.size();
29969  open_curves_pt.resize(n_open_curves);
29970  for (unsigned i = 0; i < n_open_curves; i++)
29971  {
29972  open_curves_pt[i] = tmp_open_curves_pt[i];
29973  }
29974 
29975  }
29976 #endif
29977  // ------------------------------------------
29978  // DISTRIBUTED MESH: END
29979  // ------------------------------------------
29980 
29981  // ----------------------------------------------------------------
29982  // Gather all the information and use the TriangleMeshParameters
29983  // object which help us on the manage of all TriangleMesh object's
29984  // information
29985 
29986  // Create the TriangleMeshParameters objects with the outer boundary
29987  // as the only one parameter
29988  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
29989 
29990  // Pass information about the holes
29991  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
29992 
29993  // Pass information about the internal open boundaries
29994  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
29995 
29996  // Set the element area
29997  triangle_mesh_parameters.element_area() = max_area;
29998 
29999  // Pass information about the extra holes (not defined with closed
30000  // boundaries)
30001  triangle_mesh_parameters.extra_holes_coordinates() =
30002  this->Extra_holes_coordinates;
30003 
30004  //Pass information about regions
30005  triangle_mesh_parameters.regions_coordinates() =
30006  this->Regions_coordinates;
30007 
30008  //Pass information about the using of regions
30009  if (this->Use_attributes)
30010  {
30011  triangle_mesh_parameters.enable_use_attributes();
30012  }
30013 
30014  //Pass information about allowing the creation of new points
30015  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30016  {
30017  triangle_mesh_parameters.disable_automatic_creation_of_vertices_on_boundaries();
30018  }
30019 
30020  // When the mesh is distributed we need to create a distributed
30021  // background mesh
30022 #ifdef OOMPH_HAS_MPI
30023  if (this->is_mesh_distributed())
30024  {
30025  // Mark the mesh to be created as distributed by passing a
30026  // pointer to the communicator
30027  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30028  }
30029 #endif
30030 
30031  // ----------------------------------------------------------
30032  // Build the background mesh using Triangle
30033  // ----------------------------------------------------------
30034  const double t_start_building_background_mesh =
30035  TimingHelpers::timer();
30036 
30037  if (solid_mesh_pt!=0)
30038  {
30039  tmp_new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30040  (triangle_mesh_parameters, this->Time_stepper_pt);
30041  }
30042  else
30043  {
30044  tmp_new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30045  (triangle_mesh_parameters, this->Time_stepper_pt);
30046  }
30047 
30048  if (Print_timings_level_adaptation>2)
30049  {
30050  oomph_info << "CPU for building background mesh: "
30051  <<TimingHelpers::timer()-t_start_building_background_mesh
30052  << std::endl;
30053  }
30054 
30055  // Pass the info. regarding the maximum and minimum element size
30056  // from the old mesh to the background mesh
30057  const double this_max_element_size = this->max_element_size();
30058  const double this_min_element_size = this->min_element_size();
30059  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30060  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30061 
30062  // ... also copy the minimum permitted angle
30063  const double this_min_permitted_angle = this->min_permitted_angle();
30064  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30065 
30066  // ------------------------------------------
30067  // DISTRIBUTED MESH: BEGIN
30068  // ------------------------------------------
30069 #ifdef OOMPH_HAS_MPI
30070  // If the mesh is distributed we need to pass and set the
30071  // information of internal boundaries overlaped by shared
30072  // boundaries
30073  if (this->is_mesh_distributed())
30074  {
30075  // Check if necessary to fill boundary elements for those
30076  // internal boundaries that overlap shared boundaries
30077  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30078  {
30079  // Copy the data structures that indicates which shared
30080  // boundaries are part of an internal boundary
30081  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30082  this->shared_boundary_overlaps_internal_boundary();
30083 
30084  // Copy the data structure that indicates which are the shared
30085  // boundaries in each processor
30086  tmp_new_mesh_pt->shared_boundaries_ids() =
30087  this->shared_boundaries_ids();
30088 
30089  // Fill the structures for the boundary elements and face indexes
30090  // of the boundary elements
30091  tmp_new_mesh_pt->
30092  fill_boundary_elements_and_nodes_for_internal_boundaries();
30093 
30094  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30095 
30096  } // if (this->is_mesh_distributed())
30097 #endif // #ifdef OOMPH_HAS_MPI
30098  // ------------------------------------------
30099  // DISTRIBUTED MESH: END
30100  // ------------------------------------------
30101 
30102  // Snap to curvilinear boundaries (some code duplication as this
30103  // is repeated below but helper function would take so many
30104  // arguments that it's nearly as messy...
30105 
30106  //Pass the boundary geometric objects to the new mesh
30107  tmp_new_mesh_pt->boundary_geom_object_pt() =
30108  this->boundary_geom_object_pt();
30109 
30110  //Reset the boundary coordinates if there is
30111  //a geometric object associated with the boundary
30112  tmp_new_mesh_pt->boundary_coordinate_limits() =
30113  this->boundary_coordinate_limits();
30114 
30115  const double t_start_second_stage_segments_connectivity =
30116  TimingHelpers::timer();
30117 
30118  for (unsigned b=0;b<n_boundary;b++)
30119  {
30120  // ------------------------------------------
30121  // DISTRIBUTED MESH: BEGIN
30122  // ------------------------------------------
30123 #ifdef OOMPH_HAS_MPI
30124  if (this->is_mesh_distributed())
30125  {
30126  // Identify the segments of the new mesh with the ones of the
30127  // original mesh
30128  tmp_new_mesh_pt->
30129  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30130  }
30131 #endif
30132  // ------------------------------------------
30133  // DISTRIBUTED MESH: END
30134  // ------------------------------------------
30135 
30136  // Setup boundary coordinates for boundaries with GeomObject
30137  // associated
30138  if(tmp_new_mesh_pt->boundary_geom_object_pt(b)!=0)
30139  {
30140  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30141  }
30142 
30143  }
30144 
30145  const double t_total_second_stage_segments_connectivity =
30146  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30147 
30148  const double t_start_snap_nodes_bg_mesh=TimingHelpers::timer();
30149  //Move the nodes on the new boundary onto the old curvilinear
30150  //boundary. If the boundary is straight this will do precisely
30151  //nothing but will be somewhat inefficient
30152  for(unsigned b=0;b<n_boundary;b++)
30153  {
30154  this->snap_nodes_onto_boundary(tmp_new_mesh_pt,b);
30155  }
30156 
30157  const double t_total_snap_nodes_bg_mesh=
30158  TimingHelpers::timer()-t_start_snap_nodes_bg_mesh;
30159 
30160  if (Print_timings_level_adaptation>2)
30161  {
30162  oomph_info<< "CPU for snapping nodes onto boundaries "
30163  << "(background mesh): "
30164  << t_total_snap_nodes_bg_mesh << std::endl;
30165  }
30166 
30167  // Update mesh further?
30168  if(Mesh_update_fct_pt!=0)
30169  {
30170  Mesh_update_fct_pt(tmp_new_mesh_pt);
30171  }
30172 
30173  //If we have a continuation problem
30174  //any problem in which the timestepper is a "generalisedtimestepper",
30175  //which will have been set by the problem, then ensure
30176  //all data in the new mesh has the appropriate timestepper
30177  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30178  {
30179  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30180  this->Time_stepper_pt);
30181  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30182  }*/
30183 
30184 
30185  //tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30186  //this->output("existing_mesh.dat");
30187 
30188  // ==============================================================
30189  // END: Create background mesh
30190  // ==============================================================
30191 
30192  // ==============================================================
30193  // BEGIN: Transferring of target areas and creation of new mesh
30194  // ==============================================================
30195 
30196  // Get the TriangulateIO object associated with that mesh
30197  TriangulateIO tmp_new_triangulateio =
30198  tmp_new_mesh_pt->triangulateio_representation();
30199  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30200 
30201  // If the mesh is a solid mesh then do the mapping based on the
30202  // Eulerian coordinates
30203  bool use_eulerian_coords=false;
30204  if (solid_mesh_pt!=0)
30205  {
30206  use_eulerian_coords=true;
30207  }
30208 
30209 
30210 #ifdef OOMPH_HAS_CGAL
30211 
30212  // Make cgal-based bin
30213  CGALSamplePointContainerParameters cgal_params(this);
30214  if (use_eulerian_coords)
30215  {
30216  cgal_params.enable_use_eulerian_coordinates_during_setup();
30217  }
30218  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&cgal_params);
30219 
30220 #else
30221 
30222  // Make nonrefineable bin
30223  NonRefineableBinArrayParameters params(this);
30224  if (use_eulerian_coords)
30225  {
30226  params.enable_use_eulerian_coordinates_during_setup();
30227  }
30228  Vector<unsigned> bin_dim(2);
30229  bin_dim[0]=Nbin_x_for_area_transfer;
30230  bin_dim[1]=Nbin_y_for_area_transfer;
30231  params.dimensions_of_bin_array()=bin_dim;
30232  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&params);
30233 
30234 #endif
30235 
30236  // Set up a map from pointer to element to its number
30237  // in the mesh
30238  std::map<GeneralisedElement*,unsigned> element_number;
30239  unsigned nelem=this->nelement();
30240  for (unsigned e=0;e<nelem;e++)
30241  {
30242  element_number[this->element_pt(e)]=e;
30243  }
30244 
30245 #ifndef OOMPH_HAS_CGAL
30246 
30247  // Create a vector to store the min target area of each bin (at
30248  // this stage the number of bins should not be that large, so it
30249  // should be safe to build a vector for the total number of bins)
30250  Vector<double> bin_min_target_area;
30251 
30252  // Get pointer to sample point container
30253  NonRefineableBinArray* bin_array_pt=
30254  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt->
30255  sample_point_container_pt());
30256  if (bin_array_pt==0)
30257  {
30258  throw OomphLibError(
30259  "Sample point container has to be NonRefineableBinArray",
30260  OOMPH_CURRENT_FUNCTION,
30261  OOMPH_EXCEPTION_LOCATION);
30262  }
30263 
30264  {
30265  unsigned n_bin=0;
30266  unsigned max_n_entry=0;
30267  unsigned min_n_entry=UINT_MAX;
30268  unsigned tot_n_entry=0;
30269  unsigned n_empty=0;
30270  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30271  tot_n_entry,n_empty);
30272 
30273  oomph_info << "Before bin diffusion:"
30274  << " nbin:("<<n_bin<<")"
30275  << " nempty:("<<n_empty<<")"
30276  << " min:("<<min_n_entry<<")"
30277  << " max:("<<max_n_entry<<")"
30278  << " average entries:("
30279  << double(tot_n_entry)/double(n_bin)<<")"
30280  << std::endl;
30281  }
30282 
30283  // Fill bin by diffusion
30284  double t0_bin_diff=TimingHelpers::timer();
30285  oomph_info << "Going into diffusion bit...\n";
30286  bin_array_pt->fill_bin_by_diffusion();
30287  oomph_info << "Back from diffusion bit...\n";
30288  oomph_info << "Time for bin diffusion: "
30289  << TimingHelpers::timer()-t0_bin_diff
30290  << std::endl;
30291 
30292  // Do some stats
30293  {
30294  unsigned n_bin=0;
30295  unsigned max_n_entry=0;
30296  unsigned min_n_entry=UINT_MAX;
30297  unsigned tot_n_entry=0;
30298  unsigned n_empty=0;
30299  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30300  tot_n_entry,n_empty);
30301 
30302  oomph_info << "After bin diffusion:"
30303  << " nbin:("<<n_bin<<")"
30304  << " nempty:("<<n_empty<<")"
30305  << " min:("<<min_n_entry<<")"
30306  << " max:("<<max_n_entry<<")"
30307  << " average entries:("
30308  << double(tot_n_entry)/double(n_bin)<<")"
30309  << std::endl;
30310  }
30311 
30312 
30313  // For each bin, compute the minimum of the target areas in the bin
30314 
30315  // Timing for map
30316  double t_total_map=0.0;
30317 
30318  // Counter for map
30319  unsigned counter_map = 0;
30320 
30321  // Get access to the bins (we need access to the content of the
30322  // bins to compute the minimum of the target areas of the elements
30323  // in each bin)
30324  const std::map<unsigned,Vector<std::pair<FiniteElement*,
30325  Vector<double> > > >*
30326  bins_pt=bin_array_pt->get_all_bins_content();
30327 
30328  // Get the number of bins
30329  const unsigned n_bin=bins_pt->size();
30330 
30331  // Create a vector to store the min target area of each bin (at
30332  // this stage the number of bins should not be that large, so it
30333  // should be safe to build a vector for the total number of bins)
30334  bin_min_target_area.resize(n_bin);
30335  for (unsigned u=0;u<n_bin;u++)
30336  {
30337  bin_min_target_area[u]=0.0;
30338  }
30339  // loop over the bins, get their elements and compute the minimum
30340  // target area of all of them
30341  typedef std::map<unsigned,
30342  Vector<std::pair<FiniteElement*,
30343  Vector<double> > > >::const_iterator IT;
30344  for (IT it=bins_pt->begin();it!=bins_pt->end();it++)
30345  {
30346  // The bin number
30347  unsigned ib=(*it).first;
30348 
30349  // Get the number of elements in the bin
30350  const unsigned n_ele_bin = (*it).second.size();
30351 
30352  // loop over the elements in the bin
30353  for (unsigned ee=0;ee<n_ele_bin;ee++)
30354  {
30355  // Get ee-th element (in currrent mesh) in ib-th bin
30356  GeneralisedElement* ele_pt=(*it).second[ee].first;
30357  double t_map=TimingHelpers::timer();
30358  const unsigned ele_number = element_number[ele_pt];
30359  t_total_map+=TimingHelpers::timer()-t_map;
30360 
30361  // Increase the number of calls to map
30362  counter_map++;
30363 
30364  // Go for smallest target area of any element in this bin to
30365  // force "one level" of refinement (the one-level-ness is
30366  // enforced below by limiting the actual reduction in area
30367  if (bin_min_target_area[ib]!=0)
30368  {
30369  bin_min_target_area[ib]=
30370  std::min(bin_min_target_area[ib], target_area[ele_number]);
30371  }
30372  else
30373  {
30374  bin_min_target_area[ib]=target_area[ele_number];
30375  }
30376 
30377  } // for (ee<n_ele_bin)
30378 
30379  } // for (it!=bins.end())
30380 
30381  oomph_info << "CPU for map[counter="<<counter_map<<"]: "
30382  << t_total_map << std::endl;
30383 
30384 
30385  // Optional output for debugging (keep it around!)
30386  const bool output_bins=false;
30387  if (output_bins)
30388  {
30389  unsigned length=bin_min_target_area.size();
30390  for (unsigned u = 0;u<length;u++)
30391  {
30392  oomph_info << "Bin n" << u << ",target area: "
30393  << bin_min_target_area[u]<<std::endl;
30394  }
30395  }
30396 
30397 #endif
30398 
30399 
30400  // Now start iterating to refine mesh recursively
30401  //-----------------------------------------------
30402  bool done=false;
30403  unsigned iter=0;
30404 #ifdef OOMPH_HAS_MPI
30405  // The number of elements that require (un)refinement
30406  unsigned n_ele_need_refinement = 0;
30407 #endif
30408 
30409  // The timing for the third stage of segments connectivity
30410  double t_total_third_stage_segments_connectivity = 0.0;
30411 
30412  // The timing for the transfering target areas
30413  double t_total_transfer_target_areas = 0.0;
30414 
30415  // The timing for the copying of target areas
30416  double t_total_limit_target_areas = 0.0;
30417 
30418  // The timing to create the new mesh
30419  double t_total_create_new_adapted_mesh = 0.0;
30420 
30421  // The timing for the snapping of the nodes on the new meshes
30422  double t_total_snap_nodes = 0.0;
30423 
30424  // The timing to check whether other processors need to adapt
30425  double t_total_wait_other_processors = 0.0;
30426  double t_iter=TimingHelpers::timer();
30427  while (!done)
30428  {
30429  // Accept by default but overwrite if things go wrong below
30430  done=true;
30431 
30432  double t_start_transfer_target_areas=TimingHelpers::timer();
30433  double t0_loop_int_pts=TimingHelpers::timer();
30434 
30435  // Loop over elements in new (tmp) mesh and visit all
30436  // its integration points. Check where it's located in the bin
30437  // structure of the current mesh and pass the target area
30438  // to the new element
30439  nelem=tmp_new_mesh_pt->nelement();
30440 
30441  // Store the target areas for elements in the temporary
30442  // TriangulateIO mesh
30443  Vector<double> new_transferred_target_area(nelem,0.0);
30444  for (unsigned e=0;e<nelem;e++)
30445  { // start loop el
30446  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30447  unsigned nint=el_pt->integral_pt()->nweight();
30448  for (unsigned ipt=0;ipt<nint;ipt++)
30449  {
30450  // Get the coordinate of current point
30451  Vector<double> s(2);
30452  for(unsigned i=0;i<2;i++)
30453  {
30454  s[i] = el_pt->integral_pt()->knot(ipt,i);
30455  }
30456 
30457  Vector<double> x(2);
30458  el_pt->interpolated_x(s,x);
30459 
30460 #if OOMPH_HAS_CGAL
30461 
30462  // Try the five nearest sample points for Newton search
30463  // then just settle on the nearest one
30464  GeomObject* geom_obj_pt=0;
30465  unsigned max_sample_points=
30466  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30467  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt->
30468  sample_point_container_pt())->
30469  limited_locate_zeta(x,max_sample_points,
30470  geom_obj_pt,s);
30471 #ifdef PARANOID
30472  if (geom_obj_pt==0)
30473  {
30474  std::stringstream error_message;
30475  error_message
30476  << "Limited locate zeta failed for zeta = [ "
30477  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30478  throw OomphLibError(error_message.str(),
30479  OOMPH_CURRENT_FUNCTION,
30480  OOMPH_EXCEPTION_LOCATION);
30481  }
30482  else
30483  {
30484 #endif
30485  FiniteElement* fe_pt=dynamic_cast<FiniteElement*>(geom_obj_pt);
30486 #ifdef PARANOID
30487  if (fe_pt==0)
30488  {
30489  std::stringstream error_message;
30490  error_message
30491  << "Cast to FE for GeomObject returned by limited locate zeta failed for zeta = [ "
30492  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30493  throw OomphLibError(error_message.str(),
30494  OOMPH_CURRENT_FUNCTION,
30495  OOMPH_EXCEPTION_LOCATION);
30496  }
30497  else
30498  {
30499 #endif
30500  // What's the target area of the element that contains this point
30501  double tg_area=target_area[element_number[fe_pt]];
30502 
30503  // Go for smallest target area over all integration
30504  // points in new element
30505  // to force "one level" of refinement (the one-level-ness
30506  // is enforced below by limiting the actual reduction in
30507  // area
30508  if (new_transferred_target_area[e]!=0)
30509  {
30510  new_transferred_target_area[e]=
30511  std::min(new_transferred_target_area[e],
30512  tg_area);
30513  }
30514  else
30515  {
30516  new_transferred_target_area[e]=tg_area;
30517  }
30518 #ifdef PARANOID
30519  }
30520  }
30521 #endif
30522 
30523 #else
30524 
30525  // Find the bin that contains that point and its contents
30526  int bin_number=0;
30527  bin_array_pt->get_bin(x,bin_number);
30528 
30529  // Did we find it?
30530  if (bin_number<0)
30531  {
30532  // Not even within bin boundaries... odd
30533  std::stringstream error_message;
30534  error_message
30535  << "Very odd -- we're looking for a point[ "
30536  << x[0] << " " << x[1] << " ] that's not even \n"
30537  << "located within the bin boundaries.\n";
30538  throw OomphLibError(error_message.str(),
30539  "RefineableTriangleMesh::adapt()",
30540  OOMPH_EXCEPTION_LOCATION);
30541  } // if (bin_number<0)
30542  else
30543  {
30544  // Go for smallest target area of any element in this bin
30545  // to force "one level" of refinement (the one-level-ness
30546  // is enforced below by limiting the actual reduction in
30547  // area
30548  if (new_transferred_target_area[e]!=0)
30549  {
30550  new_transferred_target_area[e]=
30551  std::min(new_transferred_target_area[e],
30552  bin_min_target_area[bin_number]);
30553  }
30554  else
30555  {
30556  new_transferred_target_area[e]=bin_min_target_area[bin_number];
30557  }
30558 
30559  }
30560 
30561 #endif
30562 
30563  } // for (ipt<nint)
30564 
30565  } // for (e<nelem)
30566 
30567 
30568  // do some output (keep it alive!)
30569  const bool output_target_areas=false;
30570  if (output_target_areas)
30571  {
30572  unsigned length=new_transferred_target_area.size();
30573  for (unsigned u = 0; u < length;u++)
30574  {
30575  oomph_info << "Element" << u << ",target area: "
30576  << new_transferred_target_area[u] << std::endl;
30577  }
30578  }
30579  oomph_info << "Time for loop over integration points in new mesh: "
30580  << TimingHelpers::timer()-t0_loop_int_pts
30581  << std::endl;
30582 
30583 
30584  // {
30585  // tmp.open((Global_string_for_annotation:: String[0]+"binned_target_areas"+
30586  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30587 
30588  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > > bin_content=
30589  // mesh_geom_obj_pt->bin_content();
30590  // unsigned nbin=bin_content.size();
30591  // for (unsigned b=0;b<nbin;b++)
30592  // {
30593  // unsigned nentry=bin_content[b].size();
30594  // for (unsigned entry=0;entry<nentry;entry++)
30595  // {
30596  // FiniteElement* el_pt=bin_content[b][entry].first;
30597  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30598  // Vector<double> s=bin_content[b][entry].second;
30599  // Vector<double> x(2);
30600  // el_pt->interpolated_x(s,x);
30601  // unsigned e_current=element_number[gen_el_pt];
30602  // tmp << x[0] << " " << x[1] << " "
30603  // << target_area[e_current] << " "
30604  // << el_pt->size() << " "
30605  // << std::endl;
30606  // }
30607  // }
30608  // tmp.close();
30609  // }
30610 
30611  const double t_sub_total_transfer_target_areas =
30612  TimingHelpers::timer()-t_start_transfer_target_areas;
30613 
30614  if (Print_timings_level_adaptation>2)
30615  {
30616  // Get the number of elements in the old mesh (this)
30617  const unsigned n_element = this->nelement();
30618  // Get the number of elements in the background mesh
30619  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30620 
30621  oomph_info << "CPU for transfer of target areas "
30622  << "[n_ele_old_mesh="
30623  << n_element <<", n_ele_background_mesh="
30624  << n_element_background<<"] (iter "<< iter << "): "
30625  << t_sub_total_transfer_target_areas<< std::endl;
30626  }
30627 
30628  // Add the timing for tranfer of target areas
30629  t_total_transfer_target_areas+=t_sub_total_transfer_target_areas;
30630 
30631  // // Output mesh
30632  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30633  // StringConversion::to_string(iter)+".dat").c_str());
30634 
30635  // tmp.open((Global_string_for_annotation:: String[0]+"target_areas_intermediate_mesh_iter"+
30636  // StringConversion::to_string(iter)+"_"+
30637  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30638 
30639  const double t_start_limit_target_areas = TimingHelpers::timer();
30640 
30641  // Now copy into target area for temporary mesh but limit to
30642  // the equivalent of one sub-division per iteration
30643 #ifdef OOMPH_HAS_MPI
30644  unsigned n_ele_need_refinement_iter = 0;
30645 #endif
30646 
30647 
30648  // Don't delete! Keep these around for debugging
30649  // ofstream tmp_mesh_file;
30650  // tmp_mesh_file.open("tmp_mesh_file.dat");
30651  // tmp_new_mesh_pt->output(tmp_mesh_file);
30652  // tmp_mesh_file.close();
30653  // ofstream target_areas_file;
30654  // target_areas_file.open("target_areas_file.dat");
30655 
30656  const unsigned nel_new=tmp_new_mesh_pt->nelement();
30657  Vector<double> new_target_area(nel_new);
30658  for (unsigned e=0;e<nel_new;e++)
30659  {
30660  // The finite element
30661  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30662 
30663  // Transferred target area
30664  const double new_area=new_transferred_target_area[e];
30665  if (new_area<=0.0)
30666  {
30667  std::ostringstream error_stream;
30668  error_stream << "This shouldn't happen! Element whose centroid is at "
30669  << (f_ele_pt->node_pt(0)->x(0)+
30670  f_ele_pt->node_pt(1)->x(0)+
30671  f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30672  << (f_ele_pt->node_pt(0)->x(1)+
30673  f_ele_pt->node_pt(1)->x(1)+
30674  f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30675  << " has no target area assigned\n";
30676  throw OomphLibError(error_stream.str(),
30677  OOMPH_CURRENT_FUNCTION,
30678  OOMPH_EXCEPTION_LOCATION);
30679  }
30680  else
30681  {
30682 
30683 
30684  // Limit target area to the equivalent of uniform refinement
30685  // during this stage of the iteration
30686  new_target_area[e]=new_area;
30687  if (new_target_area[e]<f_ele_pt->size()/3.0)
30688  {
30689  new_target_area[e]=f_ele_pt->size()/3.0;
30690 
30691  // We'll need to give it another go later
30692  done=false;
30693 
30694  }
30695 
30696  // Don't delete! Keep around for debugging
30697  // target_areas_file
30698  // << (f_ele_pt->node_pt(0)->x(0)+
30699  // f_ele_pt->node_pt(1)->x(0)+
30700  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30701  // << (f_ele_pt->node_pt(0)->x(1)+
30702  // f_ele_pt->node_pt(1)->x(1)+
30703  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30704  // << new_area << " "
30705  // << new_target_area[e] << std::endl;
30706 
30707 
30708 
30709 #ifdef OOMPH_HAS_MPI
30710  // Keep track of the elements that require (un)refinement
30711  n_ele_need_refinement_iter++;
30712 #endif
30713 
30714  } // else if (new_area <= 0.0)
30715 
30716  } // for (e < nel_new)
30717 
30718 
30719  // Don't delete! Keep around for debugging
30720  // target_areas_file.close();
30721 
30722  const double t_sub_total_limit_target_areas =
30723  TimingHelpers::timer() - t_start_limit_target_areas;
30724 
30725  // Add the timing for copying target areas
30726  t_total_limit_target_areas+=t_sub_total_limit_target_areas;
30727 
30728  if (Print_timings_level_adaptation>2)
30729  {
30730  // Get the number of elements in the old mesh (this)
30731  const unsigned n_element = this->nelement();
30732  // Get the number of elements in the background mesh
30733  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30734 
30735  oomph_info << "CPU for limiting target areas "
30736  << "[n_ele_old_mesh="
30737  << n_element <<", n_ele_background_mesh="
30738  << n_element_background<<"] (iter "<< iter << "): "
30739  << t_sub_total_limit_target_areas<< std::endl;
30740  }
30741 
30742  if (done)
30743  {
30744  oomph_info
30745  << "All area adjustments accommodated by max. permitted area"
30746  << " reduction \n";
30747  }
30748  else
30749  {
30750  oomph_info
30751  << "NOT all area adjustments accommodated by max. "
30752  << "permitted area reduction \n";
30753  }
30754 
30755  //tmp.close();
30756  //pause("doced binned_target_areas.dat and intermediate mesh targets");
30757 
30758  // Now create the new mesh from TriangulateIO structure
30759  //-----------------------------------------------------
30760  // associated with uniform background mesh and the
30761  //------------------------------------------------
30762  // associated target element sizes.
30763  //---------------------------------
30764 
30765  const double t_start_create_new_adapted_mesh =
30766  TimingHelpers::timer();
30767 
30768  // Solid mesh?
30769  if (solid_mesh_pt!=0)
30770  {
30771  new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30772  (new_target_area,
30773  tmp_new_triangulateio,
30774  this->Time_stepper_pt,
30775  this->Use_attributes,
30776  this->Allow_automatic_creation_of_vertices_on_boundaries,
30777  this->communicator_pt());
30778  }
30779  // No solid mesh
30780  else
30781  {
30782  new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30783  (new_target_area,
30784  tmp_new_triangulateio,
30785  this->Time_stepper_pt,
30786  this->Use_attributes,
30787  this->Allow_automatic_creation_of_vertices_on_boundaries,
30788  this->communicator_pt());
30789  }
30790 
30791  // Sub-total to create new adapted mesh
30792  const double t_sub_total_create_new_adapted_mesh =
30793  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
30794 
30795  // Add the time to the total snap nodes time
30796  t_total_create_new_adapted_mesh+=t_sub_total_create_new_adapted_mesh;
30797 
30798  if (Print_timings_level_adaptation>2)
30799  {
30800  // Get the number of elements of the new adapted mesh
30801  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
30802 
30803  oomph_info << "CPU for creation of new adapted mesh "
30804  << t_sub_total_create_new_adapted_mesh
30805  << "[nele="<<n_element_new_adapted_mesh
30806  << "] (iter "<< iter << "): "
30807  << t_sub_total_create_new_adapted_mesh << std::endl;
30808  }
30809 
30810 #ifdef OOMPH_HAS_MPI
30811  // ------------------------------------------
30812  // DISTRIBUTED MESH: BEGIN
30813  // ------------------------------------------
30814 
30815  // This section is only required if we are dealing with
30816  // distributed meshes, otherwise there are not shared boundaries
30817  // overlapping internal boundaries
30818 
30819  // Check if necessary to fill boundary elements for those internal
30820  // boundaries that overlap shared boundaries
30821  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30822  {
30823  // Copy the data structures that indicate which shared
30824  // boundaries are part of an internal boundary
30826  this->shared_boundary_overlaps_internal_boundary();
30827 
30828  // Copy the data structure that indicates which are the shared
30829  // boundaries in each processor
30830  new_mesh_pt->shared_boundaries_ids() =
30831  this->shared_boundaries_ids();
30832 
30833  // Fill the structures for the boundary elements and face indexes
30834  // of the boundary elements
30835  new_mesh_pt->
30836  fill_boundary_elements_and_nodes_for_internal_boundaries();
30837  }
30838  // ------------------------------------------
30839  // DISTRIBUTED MESH: END
30840  // ------------------------------------------
30841 #endif // #ifdef OOMPH_HAS_MPI
30842 
30843  // Snap to curvilinear boundaries (some code duplication as this
30844  // is repeated below but helper function would take so many
30845  // arguments that it's nearly as messy...
30846 
30847  //Pass the boundary geometric objects to the new mesh
30848  new_mesh_pt->boundary_geom_object_pt() =
30849  this->boundary_geom_object_pt();
30850 
30851  // Reset the boundary coordinates if there is
30852  // a geometric object associated with the boundary
30853  new_mesh_pt->boundary_coordinate_limits() =
30854  this->boundary_coordinate_limits();
30855 
30856  const double t_start_third_stage_segments_connectivity =
30857  TimingHelpers::timer();
30858 
30859  for (unsigned b=0;b<n_boundary;b++)
30860  {
30861  // ------------------------------------------
30862  // DISTRIBUTED MESH: BEGIN
30863  // ------------------------------------------
30864 
30865  // Before setting up boundary coordinates for the new mesh we
30866  // require to identify the segments with the old mesh to
30867  // assign initial zeta values
30868 #ifdef OOMPH_HAS_MPI
30869  if (this->is_mesh_distributed())
30870  {
30871  // Identify the segments of the new mesh with the ones of
30872  // the original mesh
30873  new_mesh_pt->
30874  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30875  }
30876 #endif
30877  // ------------------------------------------
30878  // DISTRIBUTED MESH: END
30879  // ------------------------------------------
30880 
30881  // Setup boundary coordinates for boundaries with GeomObject
30882  // associated
30883  if(new_mesh_pt->boundary_geom_object_pt(b)!=0)
30884  {
30885  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30886  }
30887 
30888  }
30889 
30890  t_total_third_stage_segments_connectivity+=
30891  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
30892 
30893  const double t_start_snap_nodes_new_mesh=TimingHelpers::timer();
30894  //Move the nodes on the new boundary onto the old curvilinear
30895  //boundary. If the boundary is straight this will do precisely
30896  //nothing but will be somewhat inefficient
30897  for(unsigned b=0;b<n_boundary;b++)
30898  {
30899  this->snap_nodes_onto_boundary(new_mesh_pt,b);
30900  }
30901 
30902  const double t_sub_total_snap_nodes_new_mesh =
30903  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
30904 
30905  // Add the time to the total snap nodes time
30906  t_total_snap_nodes+=t_sub_total_snap_nodes_new_mesh;
30907 
30908  if (Print_timings_level_adaptation>2)
30909  {
30910  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
30911  << "(iter "<<iter<<"): "
30912  << t_sub_total_snap_nodes_new_mesh<< std::endl;
30913  }
30914 
30915  // Update mesh further?
30916  if (Mesh_update_fct_pt!=0)
30917  {
30918  Mesh_update_fct_pt(new_mesh_pt);
30919  }
30920 
30921  //If we have a continuation problem
30922  //any problem in which the timestepper is a "generalisedtimestepper",
30923  //which will have been set by the problem, then ensure
30924  //all data in the new mesh has the appropriate timestepper
30925  if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30926  {
30927  new_mesh_pt->set_nodal_and_elemental_time_stepper(
30928  this->Time_stepper_pt,false);
30929  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,false);
30930  }
30931 
30932  // Not done: get ready for another iteration
30933  iter++;
30934  delete tmp_new_mesh_pt;
30935 
30936 #ifdef OOMPH_HAS_MPI
30937  // Check whether the number of elements that need (un)refinement
30938  // from the previous iteration is the same, if that is the case
30939  // then we mark this processor as done
30940  if (n_ele_need_refinement_iter == n_ele_need_refinement)
30941  {done = true;}
30942  // Update the number of elements that require further
30943  // (un)refinement
30944  n_ele_need_refinement = n_ele_need_refinement_iter;
30945 #endif // #ifdef OOMPH_HAS_MPI
30946 
30947  // ------------------------------------------
30948  // DISTRIBUTED MESH: BEGIN
30949  // ------------------------------------------
30950 
30951  // We can only finish the iteration adaptation process if ALL
30952  // the involved processor are marked as done, otherwise, ALL
30953  // processor need to go for another iteration
30954 #ifdef OOMPH_HAS_MPI
30955  if (this->is_mesh_distributed())
30956  {
30957  // Time to check whether other processors have finish to adapt
30958  const double t_start_wait_other_processors = TimingHelpers::timer();
30959 
30960  // In case that the mesh is distributed it is necessary to
30961  // verify that no processor requires further refinement. If at
30962  // least one processor needs more refinement then all
30963  // processors need to go for another iteration to participate
30964  // in the communications
30965  unsigned this_processor_requires_another_iteration = 1;
30966 
30967  // Is this processor done?
30968  if (done){this_processor_requires_another_iteration = 0;}
30969  int nproc_not_done = this_processor_requires_another_iteration;
30970  // Get the communicator of the mesh
30971  OomphCommunicator* comm_pt = this->communicator_pt();
30972  // Communicate with all procesoors to check whether we need to
30973  // re-iterate
30974  MPI_Allreduce(&this_processor_requires_another_iteration,
30975  &nproc_not_done,1,
30976  MPI_UNSIGNED,MPI_SUM,comm_pt->mpi_comm());
30977  // Are all processors done?
30978  if (nproc_not_done > 0)
30979  {
30980  oomph_info << "At least one processors requires further refinement. "
30981  << "Go for another iteration." << std::endl;
30982  done = false;
30983  }
30984 
30985  // Total to check whether other processors have finish to
30986  // adapt
30987  const double t_sub_total_wait_other_processors =
30988  TimingHelpers::timer() - t_start_wait_other_processors;
30989 
30990  // Add to the total timings to check whether other processors
30991  // need to adapt
30992  t_total_wait_other_processors+=t_sub_total_wait_other_processors;
30993 
30994  if (Print_timings_level_adaptation>2)
30995  {
30996  oomph_info << "CPU for waiting other processors "
30997  << "(iter "<<iter<<"): "
30998  << t_sub_total_wait_other_processors
30999  << std::endl;
31000  }
31001 
31002  } // if (this->is_mesh_distributed())
31003 #endif
31004  // ------------------------------------------
31005  // DISTRIBUTED MESH: END
31006  // ------------------------------------------
31007 
31008  if (!done)
31009  {
31010  oomph_info << "Going for another iteration. Current iteration ("
31011  << iter << ")" << std::endl;
31012 
31013  // Use the new mesh as the tmp mesh
31014  tmp_new_mesh_pt=new_mesh_pt;
31015  tmp_new_triangulateio=new_mesh_pt->triangulateio_representation();
31016  }
31017 
31018  } // end of iteration (while (!done))
31019 
31020  //Delete the temporary geometric object representation of the
31021  //current mesh
31022  delete mesh_geom_obj_pt;
31023 
31024  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31025  << TimingHelpers::timer()-t_iter
31026  << std::endl;
31027 
31028  if (Print_timings_level_adaptation>1)
31029  {
31030  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31031  << t_total_create_new_adapted_mesh << std::endl;
31032 
31033  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31034  << t_total_limit_target_areas << std::endl;
31035 
31036  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31037  << t_total_transfer_target_areas << std::endl;
31038 
31039  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31040  << t_total_wait_other_processors << std::endl;
31041  }
31042 
31043  // ==============================================================
31044  // END: Transferring of target areas and creation of new mesh
31045  // ==============================================================
31046 
31047  // ==============================================================
31048  // BEGIN: Project solution from the old to the new mesh
31049  // ==============================================================
31050 
31051  // Check that the projection step is not disabled
31052  if (!Disable_projection)
31053  {
31054  // Take the time for the projection step
31055  double tt_start_projection=TimingHelpers::timer();
31056 
31057  // Print info. for tranfering target areas
31058  if (Print_timings_projection)
31059  {
31060  // Switch timings and stats on
31061  Multi_domain_functions::Doc_timings=true;
31062  Multi_domain_functions::Doc_stats=true;
31063  Multi_domain_functions::Doc_full_stats=true;
31064  }
31065 
31066  double t_proj=TimingHelpers::timer();
31067  oomph_info << "About to begin projection.\n";
31068 
31069  // Project current solution onto new mesh
31070  //---------------------------------------
31071  ProjectionProblem<ELEMENT>* project_problem_pt=
31072  new ProjectionProblem<ELEMENT>;
31073 
31074  // Projection requires to be enabled as distributed if working
31075  // with a distributed mesh
31076 #ifdef OOMPH_HAS_MPI
31077  if (this->is_mesh_distributed())
31078  {
31079  // ------------------------------------------
31080  // DISTRIBUTED MESH: BEGIN
31081  // ------------------------------------------
31082 
31083  // We need to back up the time stepper object since the
31084  // projection class creates a new one
31085  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31086 
31087  // Set the projection problem as distributed
31088  project_problem_pt->enable_problem_distributed();
31089 
31090  // Pass the time stepper to the projection problem (used when
31091  // setting multi_domain_interation)
31092  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31093 
31094  // Set the mesh used for the projection object
31095  project_problem_pt->mesh_pt()=new_mesh_pt;
31096  //project_problem_pt->disable_suppress_output_during_projection();
31097 
31098  // Use iterative solver for projection? By default, an iterative
31099  // solver is used for the projection stage
31100  if(!this->use_iterative_solver_for_projection())
31101  {
31102  project_problem_pt->disable_use_iterative_solver_for_projection();
31103  }
31104 
31105  // Do the projection
31106  project_problem_pt->project(this);
31107 
31108  // Reset the time stepper object (only affects distributed meshes)
31109  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31110 
31111  // ------------------------------------------
31112  // DISTRIBUTED MESH: END
31113  // ------------------------------------------
31114 
31115  } // if (this->is_mesh_distributed())
31116  else
31117 #endif // #ifdef OOMPH_HAS_MPI
31118  {
31119  // Set the mesh used for the projection object
31120  project_problem_pt->mesh_pt()=new_mesh_pt;
31121 
31122  // project_problem_pt->disable_suppress_output_during_projection();
31123 
31124  // Use iterative solver for projection? By default, an iterative
31125  // solver is used for the projection stage
31126  if(!this->use_iterative_solver_for_projection())
31127  {
31128  project_problem_pt->disable_use_iterative_solver_for_projection();
31129  }
31130 
31131  // Do the projection
31132  project_problem_pt->project(this);
31133  }
31134 
31135  // Reset printing info. for projection
31136  if (Print_timings_projection)
31137  {
31138  // Switch timings and stats off
31139  Multi_domain_functions::Doc_timings=false;
31140  Multi_domain_functions::Doc_stats=false;
31141  Multi_domain_functions::Doc_full_stats=false;
31142  }
31143 
31144  // Get the total time for projection
31145  const double tt_projection = TimingHelpers::timer()-tt_start_projection;
31146 
31147  if (Print_timings_level_adaptation>1)
31148  {
31149  // Get the number of elements in the old mesh (this)
31150  const unsigned n_element = this->nelement();
31151  // Get the number of elements in the new mesh
31152  const unsigned n_element_new = new_mesh_pt->nelement();
31153  oomph_info << "CPU for projection (in mesh adaptation) "
31154  << "[n_ele_old_mesh="<< n_element
31155  <<", n_ele_new_mesh="<< n_element_new<<"]: "
31156  << tt_projection << std::endl;
31157 
31158  // ------------------------------------------
31159  // DISTRIBUTED MESH: BEGIN
31160  // ------------------------------------------
31161 #ifdef OOMPH_HAS_MPI
31162  if (this->is_mesh_distributed())
31163  {
31164  // The maximum number of elements in the mesh (over all
31165  // processors)
31166  unsigned n_this_element_new = n_element_new;
31167  unsigned n_max_element_new_global = 0;
31168  // Get the maximum number of elements over all processors
31169  MPI_Reduce(&n_this_element_new, &n_max_element_new_global,
31170  1, MPI_UNSIGNED, MPI_MAX, 0,
31171  this->communicator_pt()->mpi_comm());
31172 
31173  // The time for projection for this processor
31174  double tt_this_projection = tt_projection;
31175  double tt_global_min_projection = 0.0;
31176  double tt_global_max_projection = 0.0;
31177 
31178  // Get the minimum and maximum time for projection
31179  MPI_Reduce(&tt_this_projection, &tt_global_min_projection,
31180  1, MPI_DOUBLE, MPI_MIN, 0,
31181  this->communicator_pt()->mpi_comm());
31182  MPI_Reduce(&tt_this_projection, &tt_global_max_projection,
31183  1, MPI_DOUBLE, MPI_MAX, 0,
31184  this->communicator_pt()->mpi_comm());
31185 
31186  if (this->communicator_pt()->my_rank() == 0)
31187  {
31188  oomph_info << "CPU for projection global (MIN): "
31189  << tt_global_min_projection << std::endl;
31190  oomph_info << "CPU for projection global (MAX) "
31191  << "[n_max_ele_new_global="
31192  << n_max_element_new_global<<"]: "
31193  << tt_global_max_projection << std::endl;
31194 
31195  std::cerr << "CPU for projection global (MIN): "
31196  << tt_global_min_projection << std::endl;
31197  std::cerr << "CPU for projection global (MAX): "
31198  << "[n_max_ele_new_global="
31199  << n_max_element_new_global<<"]: "
31200  << tt_global_max_projection << std::endl;
31201 
31202  }
31203 
31204  }
31205 #endif // #ifdef OOMPH_HAS_MPI
31206  // ------------------------------------------
31207  // DISTRIBUTED MESH: END
31208  // ------------------------------------------
31209 
31210  } // if (Print_timings_level_adaptation>1)
31211 
31212  oomph_info << "CPU for projection of solution onto new mesh: "
31213  << TimingHelpers::timer()-t_proj
31214  << std::endl;
31215 
31216  // Delete the projection problem
31217  delete project_problem_pt;
31218 
31219  } // if (!Disable_projection)
31220  else
31221  {
31222  oomph_info << "Projection disabled! The new mesh will contain zeros"
31223  << std::endl;
31224  }
31225 
31226  // ==============================================================
31227  // END: Project solution from the old to the new mesh
31228  // ==============================================================
31229 
31230  double t_rest=TimingHelpers::timer();
31231 
31232  //Flush the old mesh
31233  unsigned nnod=nnode();
31234  for(unsigned j=nnod;j>0;j--)
31235  {
31236  delete Node_pt[j-1];
31237  Node_pt[j-1] = 0;
31238  }
31239  unsigned nel=nelement();
31240  for(unsigned e=nel;e>0;e--)
31241  {
31242  delete Element_pt[e-1];
31243  Element_pt[e-1] = 0;
31244  }
31245 
31246  // Now copy back to current mesh
31247  //------------------------------
31248  nnod=new_mesh_pt->nnode();
31249  Node_pt.resize(nnod);
31250  nel=new_mesh_pt->nelement();
31251  Element_pt.resize(nel);
31252  for(unsigned j=0;j<nnod;j++)
31253  {
31254  Node_pt[j] = new_mesh_pt->node_pt(j);
31255  }
31256  for(unsigned e=0;e<nel;e++)
31257  {
31258  Element_pt[e] = new_mesh_pt->element_pt(e);
31259  }
31260 
31261  // Copy the boundary elements information from the new mesh to the
31262  // original mesh
31263  unsigned nbound = 0;
31264 
31265 #ifdef OOMPH_HAS_MPI
31266  // If working with a distributed mesh we need to change the number
31267  // of boundaries so that shared boundaries information is also
31268  // copied from the old to the new mesh
31269  if (this->is_mesh_distributed())
31270  {
31271  // The boundaries to be copied include those new ones in the new
31272  // mesh (shared boundaries). This info. is required to
31273  // re-establish the halo/haloed scheme
31274  nbound = new_mesh_pt->nboundary();
31275  // After halo and haloed scheme has been re-established the
31276  // number of boundaries is changed to the original number of
31277  // boundaries
31278  }
31279  else
31280 #endif
31281  {
31282  // The original number of boundaries
31283  nbound = n_boundary;
31284  }
31285 
31286  Boundary_element_pt.resize(nbound);
31287  Face_index_at_boundary.resize(nbound);
31288  Boundary_node_pt.resize(nbound);
31289  for (unsigned b=0;b<nbound;b++)
31290  {
31291  unsigned nel=new_mesh_pt->nboundary_element(b);
31292  Boundary_element_pt[b].resize(nel);
31293  Face_index_at_boundary[b].resize(nel);
31294  for (unsigned e=0;e<nel;e++)
31295  {
31296  Boundary_element_pt[b][e]=new_mesh_pt->boundary_element_pt(b,e);
31297  Face_index_at_boundary[b][e]=new_mesh_pt->face_index_at_boundary(b,e);
31298  }
31299  unsigned nnod=new_mesh_pt->nboundary_node(b);
31300  Boundary_node_pt[b].resize(nnod);
31301  for (unsigned j=0;j<nnod;j++)
31302  {
31303  Boundary_node_pt[b][j]=new_mesh_pt->boundary_node_pt(b,j);
31304  }
31305  }
31306 
31307  //Also copy over the new boundary and region information
31308  unsigned n_region = new_mesh_pt->nregion();
31309  // Only bother if we have regions
31310  if(n_region > 1)
31311  {
31312  //Deal with the region information first
31313  this->Region_attribute.resize(n_region);
31314  for(unsigned r=0;r<n_region;r++)
31315  {
31316  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31317  // Get the region id
31318  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31319  //Find the number of elements in the region
31320  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31321  this->Region_element_pt[r_id].resize(n_region_element);
31322  for(unsigned e=0;e<n_region_element;e++)
31323  {
31324  this->Region_element_pt[r_id][e] =
31325  new_mesh_pt->region_element_pt(r_id,e);
31326  }
31327  }
31328 
31329  //Now the boundary region information
31330  this->Boundary_region_element_pt.resize(nbound);
31331  this->Face_index_region_at_boundary.resize(nbound);
31332 
31333  //Now loop over the boundaries
31334  for(unsigned b=0;b<nbound;++b)
31335  {
31336  for (unsigned rr = 0 ; rr < n_region; rr++)
31337  {
31338  // The region id
31339  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31340 
31341  unsigned n_boundary_el_in_region =
31342  new_mesh_pt->nboundary_element_in_region(b,r);
31343 
31344  if(n_boundary_el_in_region > 0)
31345  {
31346  //Allocate storage in the map
31347  this->Boundary_region_element_pt[b][r].
31348  resize(n_boundary_el_in_region);
31349  this->Face_index_region_at_boundary[b][r].
31350  resize(n_boundary_el_in_region);
31351 
31352  //Copy over the information
31353  for(unsigned e=0;e<n_boundary_el_in_region;++e)
31354  {
31355  this->Boundary_region_element_pt[b][r][e]
31356  = new_mesh_pt->boundary_element_in_region_pt(b,r,e);
31357  this->Face_index_region_at_boundary[b][r][e]
31358  = new_mesh_pt->face_index_at_boundary_in_region(b,r,e);
31359  }
31360  }
31361  }
31362  } //End of loop over boundaries
31363 
31364  } //End of case when more than one region
31365 
31366  // ------------------------------------------
31367  // DISTRIBUTED MESH: BEGIN
31368  // ------------------------------------------
31369 
31370  // Re-generate halo(ed) information (only for distributed meshes)
31371 #ifdef OOMPH_HAS_MPI
31372  if (this->is_mesh_distributed())
31373  {
31374  // Delete halo(ed) information in the original mesh, the new
31375  // halo(ed) information is generated usign the info. of the new
31376  // mesh
31377  if (this->is_mesh_distributed())
31378  {
31379  this->Halo_node_pt.clear();
31380  this->Root_halo_element_pt.clear();
31381 
31382  this->Haloed_node_pt.clear();
31383  this->Root_haloed_element_pt.clear();
31384 
31385  this->External_halo_node_pt.clear();
31386  this->External_halo_element_pt.clear();
31387 
31388  this->External_haloed_node_pt.clear();
31389  this->External_haloed_element_pt.clear();
31390  }
31391 
31392  // Re-establish the shared boundary elements and nodes scheme
31393  // before re-establish halo(ed) information
31394  this->reset_shared_boundary_elements_and_nodes();
31395 
31396  // -------------------------------------------------------------
31397  // Remove shared boundary elements and nodes from original
31398  // boundary elements and boundary nodes containers. Shared
31399  // boundary elements and nodes are stored in a special
31400  // container.
31401 
31402  // Get the shared boundaries in this processor with any other
31403  // processor
31404  Vector<unsigned> my_rank_shared_boundaries_ids;
31405  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
31406 
31407  // Get the number of shared boundaries
31408  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31409  // Loop over the shared boundaries marked as original boundaries
31410  // in tmp_new_mesh
31411  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31412  {
31413  // Get the boundary id
31414  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31415  // Flush any previous relation of shared boundary elements
31416  // marked as original boundary elements in tmp_new_mesh
31417  this->Boundary_element_pt[shd_bnd_id].clear();
31418 
31419  // Get the number of nodes associated with the original
31420  // boundary in tmp_new_mesh that is a shared boundary
31421  const unsigned tmp_nnodes =
31422  this->nshared_boundary_node(shd_bnd_id);
31423  for (unsigned n = 0; n < tmp_nnodes; n++)
31424  {
31425  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31426  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31427  } // for (n < nnodes)
31428 
31429  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31430 
31431  // Re-set the number of boundaries to the original one
31432  this->set_nboundary(n_boundary);
31433 
31434  // Sort the nodes on the boundaries so that they have the same
31435  // order on all the boundaries
31436  this->sort_nodes_on_shared_boundaries();
31437 
31438  // Re-set the halo(ed) scheme
31439  this->reset_halo_haloed_scheme();
31440 
31441  // Set the correct number of segments for the boundaries with
31442  // geom objects associated
31443  for (unsigned b = 0; b < n_boundary; b++)
31444  {
31445  if (this->boundary_geom_object_pt(b)!=0)
31446  {
31447  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31448  this->set_nboundary_segment_node(b, nsegments);
31449  }
31450  }
31451 
31452  // Resume the connections in boundaries were it was suspended
31453  resume_boundary_connections(resume_initial_connection_polyline_pt,
31454  resume_final_connection_polyline_pt);
31455 
31456  } // if (this->is_mesh_distributed())
31457 
31458 #endif // #ifdef OOMPH_HAS_MPI
31459 
31460  // ------------------------------------------
31461  // DISTRIBUTED MESH: END
31462  // ------------------------------------------
31463 
31464  //Snap the newly created nodes onto any geometric objects
31465  this->snap_nodes_onto_geometric_objects();
31466 
31467  // Copy the IDs of the vertex nodes
31468  this->Oomph_vertex_nodes_id=new_mesh_pt->oomph_vertex_nodes_id();
31469 
31470  // Copy TriangulateIO representation
31471  TriangleHelper::clear_triangulateio(this->Triangulateio);
31472  bool quiet=true;
31473  this->Triangulateio=
31474  TriangleHelper::deep_copy_of_triangulateio_representation(
31475  new_mesh_pt->triangulateio_representation(),quiet);
31476 
31477  // Flush the mesh
31478  new_mesh_pt->flush_element_and_node_storage();
31479 
31480  // Delete the mesh
31481  delete new_mesh_pt;
31482 
31483  // Resume of timings
31484  if (Print_timings_level_adaptation>2)
31485  {
31486  // Report timings related with setting boundary coordinates of
31487  // nodes on segments
31488  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31489  << t_total_first_stage_segments_connectivity << std::endl;
31490  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31491  << t_total_second_stage_segments_connectivity << std::endl;
31492  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31493  << t_total_third_stage_segments_connectivity << std::endl;
31494  }
31495 
31496  if (Print_timings_level_adaptation>1)
31497  {
31498  const double t_total_segments_connectivity =
31499  t_total_first_stage_segments_connectivity +
31500  t_total_second_stage_segments_connectivity +
31501  t_total_third_stage_segments_connectivity;
31502 
31503  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31504  << t_total_segments_connectivity << std::endl;
31505 
31506  if (Print_timings_level_adaptation>2)
31507  {
31508  // Report timings for snapping of nodes onto boundaries
31509  oomph_info << "CPU for snapping nodes onto boundaries "
31510  << "(new mesh): "
31511  << t_total_snap_nodes << std::endl;
31512  }
31513 
31514  t_total_snap_nodes+=t_total_snap_nodes_bg_mesh;
31515  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31516  << t_total_snap_nodes << std::endl;
31517  }
31518 
31519  double max_area=0.0;
31520  double min_area=0.0;
31521 
31522  this->max_and_min_element_size(max_area, min_area);
31523  oomph_info << "Max/min element size in adapted mesh: "
31524  << max_area << " "
31525  << min_area << std::endl;
31526 
31527  oomph_info << "CPU time for final bits [sec]: "
31528  << TimingHelpers::timer()-t_rest
31529  << std::endl;
31530  }
31531  else
31532  {
31533  oomph_info << "Not enough benefit in adaptation.\n";
31534  Nrefined=0;
31535  Nunrefined=0;
31536  }
31537 
31538  double CPU_for_adaptation = TimingHelpers::timer()-t_start_overall;
31539  oomph_info <<"CPU time for adaptation [sec]: "
31540  << CPU_for_adaptation << std::endl;
31541 
31542  // ------------------------------------------
31543  // DISTRIBUTED MESH: BEGIN
31544  // ------------------------------------------
31545 #ifdef OOMPH_HAS_MPI
31546  if (this->is_mesh_distributed())
31547  {
31548  // Get the communicator
31549  OomphCommunicator* comm_pt = this->communicator_pt();
31550  // Get the total number of processors to compute the average
31551  const unsigned n_proc = comm_pt->nproc();
31552  if (Print_timings_level_adaptation>1 && n_proc>1)
31553  {
31554  double global_min_CPU_for_adaptation = 0.0;
31555  double global_max_CPU_for_adaptation = 0.0;
31556  double global_average_CPU_for_adaptation = 0.0;
31557 
31558  // Get the maximum and minimum of the adaptation times
31559  MPI_Reduce(&CPU_for_adaptation, &global_min_CPU_for_adaptation,
31560  1, MPI_DOUBLE, MPI_MIN, 0, comm_pt->mpi_comm());
31561  MPI_Reduce(&CPU_for_adaptation, &global_max_CPU_for_adaptation,
31562  1, MPI_DOUBLE, MPI_MAX, 0, comm_pt->mpi_comm());
31563  MPI_Reduce(&CPU_for_adaptation, &global_average_CPU_for_adaptation,
31564  1, MPI_DOUBLE, MPI_SUM, 0, comm_pt->mpi_comm());
31565 
31566  // Get the rank of the processor
31567  const unsigned my_rank = comm_pt->my_rank();
31568  if (my_rank==0)
31569  {
31570  oomph_info << "CPU for adaptation (MIN): "
31571  << global_min_CPU_for_adaptation << std::endl;
31572  oomph_info << "CPU for adaptation (MAX): "
31573  << global_max_CPU_for_adaptation << std::endl;
31574  oomph_info << "CPU for adaptation (AVERAGE): "
31575  << global_average_CPU_for_adaptation/n_proc << std::endl;
31576  } // if (my_rank==0)
31577 
31578  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31579 
31580  } // if (this->is_mesh_distributed())
31581 
31582  // ------------------------------------------
31583  // DISTRIBUTED MESH: END
31584  // ------------------------------------------
31585 
31586 #endif // #ifdef OOMPH_HAS_MPI
31587 
31588 
31589 
31590  }
31591 
31592 //=========================================================================
31593  /// \ short Mark the vertices that are not allowed for deletion by
31594  /// the unrefienment/refinement polyline methods. In charge of
31595  /// filling the Boundary_connections_pt structure
31596  //=========================================================================
31597  template<class ELEMENT>
31599  {
31600  // Clear any previous information
31601  //Boundary_chunk_connections_pt.clear();
31602  Boundary_connections_pt.clear();
31603 
31604  // Loop over the boundaries in the domain (outer, internal -- closed
31605  // and open ---, and shared) and get the boundaries ids with
31606  // connections (have or receive)
31607 
31608  // Store the boundaries ids that have or receive connection
31609  std::set<unsigned> boundary_id_with_connections;
31610 
31611  // ------------------------------------------------------------------
31612  // Outer boundaries
31613  // ------------------------------------------------------------------
31614 
31615  // Get the number of outer boundaries (closed boundaries)
31616  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31617 
31618  // Loop over the outer boundaries
31619  for (unsigned i = 0; i < n_outer_boundaries; i++)
31620  {
31621  // Get a temporary polygon representation
31622  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31623  // Get the number of polylines associated to the current outer
31624  // boundary
31625  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31626  // Loop over the polylines
31627  for (unsigned p = 0; p < n_polyline; p++)
31628  {
31629  // Get a temporary representation of the polyline
31630  TriangleMeshPolyLine* tmp_polyline_pt =
31631  tmp_polygon_pt->polyline_pt(p);
31632 
31633  // Is the initial vertex connected?
31634  if (tmp_polyline_pt->is_initial_vertex_connected())
31635  {
31636  // Get the boundary id of the current polyline
31637  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31638 
31639  // Include the boundary id to the set of boundaries with
31640  // connections
31641  boundary_id_with_connections.insert(bnd_id);
31642 
31643  // Boundary id to which the curve is connecte
31644  const unsigned dst_bnd_id =
31645  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31646 
31647  // Include the destination boundary id to the set of
31648  // boundaries with connections
31649  boundary_id_with_connections.insert(dst_bnd_id);
31650 
31651  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31652 
31653  // Is the final vertex connected?
31654  if (tmp_polyline_pt->is_final_vertex_connected())
31655  {
31656  // Get the boundary id of the current polyline
31657  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31658 
31659  // Include the boundary id to the set of boundaries with
31660  // connections
31661  boundary_id_with_connections.insert(bnd_id);
31662 
31663  // Boundary id to which the curve is connected
31664  const unsigned dst_bnd_id =
31665  tmp_polyline_pt->final_vertex_connected_bnd_id();
31666 
31667  // Include the destination boundary id to the set of
31668  // boundaries with connections
31669  boundary_id_with_connections.insert(dst_bnd_id);
31670 
31671  } // if (tmp_polyline_pt->is_final_vertex_connected())
31672 
31673  } // for (p < n_polyline)
31674 
31675  } // for (i < n_outer_boundaries)
31676 
31677  // ------------------------------------------------------------------
31678  // Internal boundaries
31679  // ------------------------------------------------------------------
31680 
31681  // Get the number of internal boundaries (closed boundaries)
31682  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31683 
31684  // Loop over the internal boundaries
31685  for (unsigned i = 0; i < n_internal_boundaries; i++)
31686  {
31687  // Get a temporary polygon representation
31688  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31689  // Get the number of polylines associated to the current internal
31690  // boundary
31691  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31692  // Loop over the polylines
31693  for (unsigned p = 0; p < n_polyline; p++)
31694  {
31695  // Get a temporary representation of the polyline
31696  TriangleMeshPolyLine* tmp_polyline_pt =
31697  tmp_polygon_pt->polyline_pt(p);
31698 
31699  // Is the initial vertex connected?
31700  if (tmp_polyline_pt->is_initial_vertex_connected())
31701  {
31702  // Get the boundary id of the current polyline
31703  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31704 
31705  // Include the boundary id to the set of boundaries with
31706  // connections
31707  boundary_id_with_connections.insert(bnd_id);
31708 
31709  // Boundary id to which the curve is connecte
31710  const unsigned dst_bnd_id =
31711  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31712 
31713  // Include the destination boundary id to the set of
31714  // boundaries with connections
31715  boundary_id_with_connections.insert(dst_bnd_id);
31716 
31717  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31718 
31719  // Is the final vertex connected?
31720  if (tmp_polyline_pt->is_final_vertex_connected())
31721  {
31722  // Get the boundary id of the current polyline
31723  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31724 
31725  // Include the boundary id to the set of boundaries with
31726  // connections
31727  boundary_id_with_connections.insert(bnd_id);
31728 
31729  // Boundary id to which the curve is connected
31730  const unsigned dst_bnd_id =
31731  tmp_polyline_pt->final_vertex_connected_bnd_id();
31732 
31733  // Include the destination boundary id to the set of
31734  // boundaries with connections
31735  boundary_id_with_connections.insert(dst_bnd_id);
31736 
31737  } // if (tmp_polyline_pt->is_final_vertex_connected())
31738 
31739  } // for (p < n_polyline)
31740 
31741  } // for (i < n_internal_boundaries)
31742 
31743  // ------------------------------------------------------------------
31744  // Open boundaries (nonclosed internal boundaries)
31745  // ------------------------------------------------------------------
31746 
31747  // Get the number of internal boundaries (open boundaries)
31748  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
31749 
31750  // Loop over the internal open boundaries
31751  for (unsigned i = 0; i < n_open_boundaries; i++)
31752  {
31753  // Get a temporary representation for the open curve
31754  TriangleMeshOpenCurve* tmp_open_curve_pt =
31755  this->Internal_open_curve_pt[i];
31756 
31757  // Get the number of curve sections associated to the current
31758  // internal open boundary
31759  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
31760 
31761  // Loop over the curve section
31762  for (unsigned p = 0; p < n_curve_section; p++)
31763  {
31764  // Get a temporary representation of the curve section
31765  // (polyline)
31766  TriangleMeshPolyLine* tmp_polyline_pt =
31767  tmp_open_curve_pt->polyline_pt(p);
31768 
31769  // Is the initial vertex connected?
31770  if (tmp_polyline_pt->is_initial_vertex_connected())
31771  {
31772  // Get the boundary id of the current polyline
31773  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31774 
31775  // Include the boundary id to the set of boundaries with
31776  // connections
31777  boundary_id_with_connections.insert(bnd_id);
31778 
31779  // Boundary id to which the curve is connecte
31780  const unsigned dst_bnd_id =
31781  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31782 
31783  // Include the destination boundary id to the set of
31784  // boundaries with connections
31785  boundary_id_with_connections.insert(dst_bnd_id);
31786 
31787  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31788 
31789  // Is the final vertex connected?
31790  if (tmp_polyline_pt->is_final_vertex_connected())
31791  {
31792  // Get the boundary id of the current polyline
31793  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31794 
31795  // Include the boundary id to the set of boundaries with
31796  // connections
31797  boundary_id_with_connections.insert(bnd_id);
31798 
31799  // Boundary id to which the curve is connected
31800  const unsigned dst_bnd_id =
31801  tmp_polyline_pt->final_vertex_connected_bnd_id();
31802 
31803  // Include the destination boundary id to the set of
31804  // boundaries with connections
31805  boundary_id_with_connections.insert(dst_bnd_id);
31806 
31807  } // if (tmp_polyline_pt->is_final_vertex_connected())
31808 
31809  } // for (p < n_curve_section)
31810 
31811  } // for (i < n_open_boundaries)
31812 
31813 #ifdef OOMPH_HAS_MPI
31814  // ------------------------------------------------------------------
31815  // Shared boundaries (only for distributed meshes)
31816  // ------------------------------------------------------------------
31817 
31818  // Check if we need to include any information associated with
31819  // shared boundaries
31820  if (this->is_mesh_distributed())
31821  {
31822  // Get the rank of the current processor
31823  const unsigned my_rank = this->communicator_pt()->my_rank();
31824 
31825  // Get the number of shared curves in the current processor
31826  const unsigned n_shared_curves =
31827  this->nshared_boundary_curves(my_rank);
31828 
31829  // Loop over the shared curves
31830  for (unsigned i = 0; i < n_shared_curves; i ++)
31831  {
31832  // Get the number of polylines associated to the current shared
31833  // curve
31834  const unsigned n_polyline =
31835  this->nshared_boundary_polyline(my_rank, i);
31836 
31837  // Loop over the polylines associated to the current shared
31838  // curve
31839  for (unsigned p = 0; p < n_polyline; p++)
31840  {
31841  // Get a temporary representation of the shared polyline
31842  TriangleMeshPolyLine* tmp_polyline_pt =
31843  this->shared_boundary_polyline_pt(my_rank, i, p);
31844 
31845  // Is the initial vertex connected?
31846  if (tmp_polyline_pt->is_initial_vertex_connected())
31847  {
31848  // Get the boundary id of the current polyline
31849  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31850 
31851  // Include the boundary id to the set of boundaries with
31852  // connections
31853  boundary_id_with_connections.insert(bnd_id);
31854 
31855  // Boundary id to which the curve is connecte
31856  const unsigned dst_bnd_id =
31857  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31858 
31859  // Include the destination boundary id to the set of
31860  // boundaries with connections
31861  boundary_id_with_connections.insert(dst_bnd_id);
31862 
31863  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31864 
31865  // Is the final vertex connected?
31866  if (tmp_polyline_pt->is_final_vertex_connected())
31867  {
31868  // Get the boundary id of the current polyline
31869  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31870 
31871  // Include the boundary id to the set of boundaries with
31872  // connections
31873  boundary_id_with_connections.insert(bnd_id);
31874 
31875  // Boundary id to which the curve is connected
31876  const unsigned dst_bnd_id =
31877  tmp_polyline_pt->final_vertex_connected_bnd_id();
31878 
31879  // Include the destination boundary id to the set of
31880  // boundaries with connections
31881  boundary_id_with_connections.insert(dst_bnd_id);
31882 
31883  } // if (tmp_polyline_pt->is_final_vertex_connected())
31884 
31885  } // for (p < n_polyline)
31886 
31887  } // for (i < n_shared_curves)
31888 
31889  } // if (this->is_mesh_distributed())
31890 
31891 #endif // #ifdef OOMPH_HAS_MPI
31892 
31893  // ---------------------------------------------------------------
31894  // Get the nodes sorted by segments of the boundaries with
31895  // connections
31896 
31897  // Store the sorted nodes by segments of the boundaries with
31898  // connections
31899  std::map<unsigned, Vector<Vector<Node*> > > bnd_sorted_segment_node_pt;
31900 
31901  // Loop over the boundaries with connections
31902  for (std::set<unsigned>::iterator it =
31903  boundary_id_with_connections.begin();
31904  it != boundary_id_with_connections.end(); it++)
31905  {
31906  // Get the boundary id
31907  const unsigned bnd_id = (*it);
31908 #ifdef OOMPH_HAS_MPI
31909  // Working with a distributed mesh
31910  if (this->is_mesh_distributed())
31911  {
31912  // Get the initial shared boundary id
31913  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
31914  // Is an original or shared boundary
31915  if (bnd_id >= init_shd_bnd_id)
31916  {
31917  // Is a shared boundary
31918 
31919  // Temporary storage for the nodes on the shared boundary
31920  Vector<Vector<Node*> > tmp_shared_nodes_pt;
31921 
31922  // Get the nodes associated to the shared boundary
31923  get_shared_boundary_segment_nodes_helper(bnd_id,
31924  tmp_shared_nodes_pt);
31925 
31926  // Store the nodes associated to the shared boundary
31927  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
31928 
31929  } // if (bnd_id >= init_shd_bnd_id)
31930  else
31931  {
31932  // Is an original boundary
31933 
31934  // Temporary storage for the nodes on the original boundary
31935  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31936 
31937  // Get the nodes associated to the shared boundary
31938  get_boundary_segment_nodes_helper(bnd_id,
31939  tmp_boundary_nodes_pt);
31940 
31941  // Store the nodes associated to the shared boundary
31942  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31943 
31944  } // if (bnd_id >= init_shd_bnd_id)
31945 
31946  } // if (this->is_mesh_distributed())
31947  else
31948 #endif // #ifdef OOMPH_HAS_MPI
31949  {
31950  // Is an original boundary
31951 
31952  // Temporary storage for the nodes on the original boundary
31953  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31954 
31955  // Get the nodes associated to the shared boundary
31956  get_boundary_segment_nodes_helper(bnd_id,
31957  tmp_boundary_nodes_pt);
31958 
31959  // Store the nodes associated to the shared boundary
31960  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31961 
31962  } // if (this->is_mesh_distributed())
31963 
31964  } // Loop over boundaries with connections
31965 
31966  // -----------------------------------------------------------------
31967  // Loop again over the boundaries (original and shared) and search
31968  // for the repeated nodes in those boundaries with connections
31969 
31970  // ------------------------------------------------------------------
31971  // Outer boundaries
31972  // ------------------------------------------------------------------
31973  // Loop over the outer boundaries
31974  for (unsigned i = 0; i < n_outer_boundaries; i++)
31975  {
31976  // Get a temporary polygon representation
31977  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31978  // Get the number of polylines associated to the current outer
31979  // boundary
31980  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31981  // Loop over the polylines
31982  for (unsigned p = 0; p < n_polyline; p++)
31983  {
31984  // Get a temporary representation of the polyline
31985  TriangleMeshPolyLine* tmp_polyline_pt =
31986  tmp_polygon_pt->polyline_pt(p);
31987 
31988  // Is the initial vertex connected?
31989  if (tmp_polyline_pt->is_initial_vertex_connected())
31990  {
31991  // Get the boundary id of the current polyline
31992  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31993 
31994  // Boundary id to which the curve is connected
31995  const unsigned dst_bnd_id =
31996  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31997 
31998  // Boundary chunk to which the curve is connected
31999  const unsigned dst_chunk =
32000  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32001 
32002  // Get the nodes representation of the current boundary
32003  Vector<Vector<Node*> > src_bnd_node_pt =
32004  bnd_sorted_segment_node_pt[bnd_id];
32005 
32006  // Get the nodes representation of the boundary to connect
32007  Vector<Vector<Node*> > dst_bnd_node_pt =
32008  bnd_sorted_segment_node_pt[dst_bnd_id];
32009 
32010  // Add the repeated node to the list of non delete-able
32011  // vertices
32012  add_non_delete_vertices_from_boundary_helper(
32013  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32014 
32015  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32016 
32017  // Is the final vertex connected?
32018  if (tmp_polyline_pt->is_final_vertex_connected())
32019  {
32020  // Get the boundary id of the current polyline
32021  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32022 
32023  // Boundary id to which the curve is connected
32024  const unsigned dst_bnd_id =
32025  tmp_polyline_pt->final_vertex_connected_bnd_id();
32026 
32027  // Boundary chunk to which the curve is connected
32028  const unsigned dst_chunk =
32029  tmp_polyline_pt->final_vertex_connected_n_chunk();
32030 
32031  // Get the nodes representation of the current boundary
32032  Vector<Vector<Node*> > src_bnd_node_pt =
32033  bnd_sorted_segment_node_pt[bnd_id];
32034 
32035  // Get the nodes representation of the boundary to connect
32036  Vector<Vector<Node*> > dst_bnd_node_pt =
32037  bnd_sorted_segment_node_pt[dst_bnd_id];
32038 
32039  // Add the repeated node to the list of non delete-able
32040  // vertices
32041  add_non_delete_vertices_from_boundary_helper(
32042  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32043 
32044  } // if (tmp_polyline_pt->is_final_vertex_connected())
32045 
32046  } // for (p < n_polyline)
32047 
32048  } // for (i < n_outer_boundaries)
32049 
32050  // ------------------------------------------------------------------
32051  // Internal boundaries
32052  // ------------------------------------------------------------------
32053  // Loop over the internal boundaries
32054  for (unsigned i = 0; i < n_internal_boundaries; i++)
32055  {
32056  // Get a temporary polygon representation
32057  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32058  // Get the number of polylines associated to the current internal
32059  // boundary
32060  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32061  // Loop over the polylines
32062  for (unsigned p = 0; p < n_polyline; p++)
32063  {
32064  // Get a temporary representation of the polyline
32065  TriangleMeshPolyLine* tmp_polyline_pt =
32066  tmp_polygon_pt->polyline_pt(p);
32067 
32068  // Is the initial vertex connected?
32069  if (tmp_polyline_pt->is_initial_vertex_connected())
32070  {
32071  // Get the boundary id of the current polyline
32072  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32073 
32074  // Boundary id to which the curve is connected
32075  const unsigned dst_bnd_id =
32076  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32077 
32078  // Boundary chunk to which the curve is connected
32079  const unsigned dst_chunk =
32080  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32081 
32082  // Get the nodes representation of the current boundary
32083  Vector<Vector<Node*> > src_bnd_node_pt =
32084  bnd_sorted_segment_node_pt[bnd_id];
32085 
32086  // Get the nodes representation of the boundary to connect
32087  Vector<Vector<Node*> > dst_bnd_node_pt =
32088  bnd_sorted_segment_node_pt[dst_bnd_id];
32089 
32090  // Add the repeated node to the list of non delete-able
32091  // vertices
32092  add_non_delete_vertices_from_boundary_helper(
32093  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32094 
32095  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32096 
32097  // Is the final vertex connected?
32098  if (tmp_polyline_pt->is_final_vertex_connected())
32099  {
32100  // Get the boundary id of the current polyline
32101  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32102 
32103  // Boundary id to which the curve is connected
32104  const unsigned dst_bnd_id =
32105  tmp_polyline_pt->final_vertex_connected_bnd_id();
32106 
32107  // Boundary chunk to which the curve is connected
32108  const unsigned dst_chunk =
32109  tmp_polyline_pt->final_vertex_connected_n_chunk();
32110 
32111  // Get the nodes representation of the current boundary
32112  Vector<Vector<Node*> > src_bnd_node_pt =
32113  bnd_sorted_segment_node_pt[bnd_id];
32114 
32115  // Get the nodes representation of the boundary to connect
32116  Vector<Vector<Node*> > dst_bnd_node_pt =
32117  bnd_sorted_segment_node_pt[dst_bnd_id];
32118 
32119  // Add the repeated node to the list of non delete-able
32120  // vertices
32121  add_non_delete_vertices_from_boundary_helper(
32122  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32123 
32124  } // if (tmp_polyline_pt->is_final_vertex_connected())
32125 
32126  } // for (p < n_polyline)
32127 
32128  } // for (i < n_internal_boundaries)
32129 
32130  // ------------------------------------------------------------------
32131  // Open boundaries (nonclosed internal boundaries)
32132  // ------------------------------------------------------------------
32133  // Loop over the internal open boundaries
32134  for (unsigned i = 0; i < n_open_boundaries; i++)
32135  {
32136  // Get a temporary representation for the open curve
32137  TriangleMeshOpenCurve* tmp_open_curve_pt =
32138  this->Internal_open_curve_pt[i];
32139 
32140  // Get the number of curve sections associated to the current
32141  // internal open boundary
32142  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32143 
32144  // Loop over the curve section
32145  for (unsigned p = 0; p < n_curve_section; p++)
32146  {
32147  // Get a temporary representation of the curve section
32148  // (polyline)
32149  TriangleMeshPolyLine* tmp_polyline_pt =
32150  tmp_open_curve_pt->polyline_pt(p);
32151 
32152  // Is the initial vertex connected?
32153  if (tmp_polyline_pt->is_initial_vertex_connected())
32154  {
32155  // Get the boundary id of the current polyline
32156  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32157 
32158  // Boundary id to which the curve is connected
32159  const unsigned dst_bnd_id =
32160  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32161 
32162  // Boundary chunk to which the curve is connected
32163  const unsigned dst_chunk =
32164  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32165 
32166  // Get the nodes representation of the current boundary
32167  Vector<Vector<Node*> > src_bnd_node_pt =
32168  bnd_sorted_segment_node_pt[bnd_id];
32169 
32170  // Get the nodes representation of the boundary to connect
32171  Vector<Vector<Node*> > dst_bnd_node_pt =
32172  bnd_sorted_segment_node_pt[dst_bnd_id];
32173 
32174  // Add the repeated node to the list of non delete-able
32175  // vertices
32176  add_non_delete_vertices_from_boundary_helper(
32177  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32178 
32179  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32180 
32181  // Is the final vertex connected?
32182  if (tmp_polyline_pt->is_final_vertex_connected())
32183  {
32184  // Get the boundary id of the current polyline
32185  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32186 
32187  // Boundary id to which the curve is connected
32188  const unsigned dst_bnd_id =
32189  tmp_polyline_pt->final_vertex_connected_bnd_id();
32190 
32191  // Boundary chunk to which the curve is connected
32192  const unsigned dst_chunk =
32193  tmp_polyline_pt->final_vertex_connected_n_chunk();
32194 
32195  // Get the nodes representation of the current boundary
32196  Vector<Vector<Node*> > src_bnd_node_pt =
32197  bnd_sorted_segment_node_pt[bnd_id];
32198 
32199  // Get the nodes representation of the boundary to connect
32200  Vector<Vector<Node*> > dst_bnd_node_pt =
32201  bnd_sorted_segment_node_pt[dst_bnd_id];
32202 
32203  // Add the repeated node to the list of non delete-able
32204  // vertices
32205  add_non_delete_vertices_from_boundary_helper(
32206  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32207 
32208  } // if (tmp_polyline_pt->is_final_vertex_connected())
32209 
32210  } // for (p < n_curve_section)
32211 
32212  } // for (i < n_open_boundaries)
32213 
32214 #ifdef OOMPH_HAS_MPI
32215  // ------------------------------------------------------------------
32216  // Shared boundaries (only for distributed meshes)
32217  // ------------------------------------------------------------------
32218 
32219  // Check if we need to include any information associated with
32220  // shared boundaries
32221  if (this->is_mesh_distributed())
32222  {
32223  // Get the rank of the current processor
32224  const unsigned my_rank = this->communicator_pt()->my_rank();
32225 
32226  // Get the number of shared curves in the current processor
32227  const unsigned n_shared_curves =
32228  this->nshared_boundary_curves(my_rank);
32229 
32230  // Loop over the shared curves
32231  for (unsigned i = 0; i < n_shared_curves; i ++)
32232  {
32233  // Get the number of polylines associated to the current shared
32234  // curve
32235  const unsigned n_polyline =
32236  this->nshared_boundary_polyline(my_rank, i);
32237 
32238  // Loop over the polylines associated to the current shared
32239  // curve
32240  for (unsigned p = 0; p < n_polyline; p++)
32241  {
32242  // Get a temporary representation of the shared polyline
32243  TriangleMeshPolyLine* tmp_polyline_pt =
32244  this->shared_boundary_polyline_pt(my_rank, i, p);
32245 
32246  // Is the initial vertex connected?
32247  if (tmp_polyline_pt->is_initial_vertex_connected())
32248  {
32249  // Get the boundary id of the current polyline
32250  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32251 
32252  // Boundary id to which the curve is connected
32253  const unsigned dst_bnd_id =
32254  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32255 
32256  // Boundary chunk to which the curve is connected
32257  const unsigned dst_chunk =
32258  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32259 
32260  // Get the nodes representation of the current boundary
32261  Vector<Vector<Node*> > src_bnd_node_pt =
32262  bnd_sorted_segment_node_pt[bnd_id];
32263 
32264  // Get the nodes representation of the boundary to connect
32265  Vector<Vector<Node*> > dst_bnd_node_pt =
32266  bnd_sorted_segment_node_pt[dst_bnd_id];
32267 
32268  // Add the repeated node to the list of non delete-able
32269  // vertices
32270  add_non_delete_vertices_from_boundary_helper(
32271  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32272 
32273  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32274 
32275  // Is the final vertex connected?
32276  if (tmp_polyline_pt->is_final_vertex_connected())
32277  {
32278  // Get the boundary id of the current polyline
32279  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32280 
32281  // Boundary id to which the curve is connected
32282  const unsigned dst_bnd_id =
32283  tmp_polyline_pt->final_vertex_connected_bnd_id();
32284 
32285  // Boundary chunk to which the curve is connected
32286  const unsigned dst_chunk =
32287  tmp_polyline_pt->final_vertex_connected_n_chunk();
32288 
32289  // Get the nodes representation of the current boundary
32290  Vector<Vector<Node*> > src_bnd_node_pt =
32291  bnd_sorted_segment_node_pt[bnd_id];
32292 
32293  // Get the nodes representation of the boundary to connect
32294  Vector<Vector<Node*> > dst_bnd_node_pt =
32295  bnd_sorted_segment_node_pt[dst_bnd_id];
32296 
32297  // Add the repeated node to the list of non delete-able
32298  // vertices
32299  add_non_delete_vertices_from_boundary_helper(
32300  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32301 
32302  } // if (tmp_polyline_pt->is_final_vertex_connected())
32303 
32304  } // for (p < n_polyline)
32305 
32306  } // for (i < n_shared_curves)
32307 
32308  } // if (this->is_mesh_distributed())
32309 
32310 #endif // #ifdef OOMPH_HAS_MPI
32311 
32312  }
32313 
32314  //=========================================================================
32315  /// \short Adds the vertices from the sources boundary that are
32316  /// repeated in the destination boundary to the list of non
32317  /// delete-able vertices in the destination boundary
32318  //=========================================================================
32319  template<class ELEMENT>
32322  Vector<Vector<Node*> > src_bound_segment_node_pt,
32323  Vector<Vector<Node*> > dst_bound_segment_node_pt,
32324  const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
32325  {
32326  // Get the number of segments in the source boundary
32327  const unsigned n_seg = src_bound_segment_node_pt.size();
32328  // Loop over the segments in the source boundary
32329  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32330  {
32331  // Get the number of nodes in the current segment
32332  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32333  // Get the left and right node of the current segment
32334  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32335  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode-1];
32336 
32337  // Get the number of segments in the destination boundary
32338  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32339  // Loop over the segments in the destination boundary
32340  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32341  {
32342  // Get the number of nodes on the current destination segment
32343  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32344  // Loop over the nodes until the node has been found or we have
32345  // visited all the nodes
32346  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32347  {
32348  // Get a pointer to the jnode in the destination segment
32349  // boundary
32350  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32351  // Is the node the same as the left or right node if
32352  // the source segment boundary
32353  if (tmp_node_pt == left_node_pt)
32354  {
32355  // We have foud the node to connect, get the vertex of the node
32356  Vector<double> vertex(2);
32357  vertex[0] = tmp_node_pt->x(0);
32358  vertex[1] = tmp_node_pt->x(1);
32359 
32360  // Establish the vertex coordinate as untouchable in the
32361  // destination boundary during the adaptation process. It
32362  // means that unrefinement can not take off the vertices
32363  // that receive connections in the destination boundary
32364  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32365  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32366  // insert(vertex);
32367 
32368  // return
32369  return;
32370 
32371  } // if (tmp_node_pt == left_node_pt)
32372  else if (tmp_node_pt == right_node_pt)
32373  {
32374  // We have foud the node to connect, get the vertex of the node
32375  Vector<double> vertex(2);
32376  vertex[0] = tmp_node_pt->x(0);
32377  vertex[1] = tmp_node_pt->x(1);
32378 
32379  // Establish the vertex coordinate as untouchable in the
32380  // destination boundary during the adaptation process. It
32381  // means that unrefinement can not take off the vertices
32382  // that receive connections in the destination boundary
32383  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32384  // insert(vertex);
32385  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32386 
32387  // return
32388  return;
32389 
32390  } // else if (tmp_node_pt == right_node_pt)
32391 
32392  } // for (jnode < n_dst_node)
32393 
32394  } // for (jseg < n_dst_seg)
32395 
32396  } // for (iseg < n_seg)
32397 
32398  }
32399 
32400 #ifdef OOMPH_HAS_MPI
32401  //=========================================================================
32402  /// \short Synchronise the vertices that are marked for non deletion
32403  // on the shared boundaries. Unrefinement of shared boundaries is
32404  // performed only if the candidate node is not marked for non deletion
32405  //=========================================================================
32406  template<class ELEMENT>
32409  {
32410  // Get the number of processors
32411  const unsigned nproc = this->communicator_pt()->nproc();
32412  // Get my rank
32413  const unsigned my_rank = this->communicator_pt()->my_rank();
32414 
32415  // loop over the processors
32416  for (unsigned jproc = 0; jproc < nproc; jproc++)
32417  {
32418  // The number of boundaries shared with the current processor
32419  // (if jproc==my_rank then there are no shared boundaries
32420  // between them)
32421  const unsigned n_shd_bnd_jproc =
32422  this->nshared_boundaries(my_rank, jproc);
32423 
32424  // Are there shared boundaries with the jproc processor?
32425  // There are no info. with myself
32426  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32427  {
32428  // Storage for the boundaries ids with vertices for non
32429  // deletion
32430  Vector<unsigned> shd_bnd_id_for_non_deletion;
32431 
32432  // Storage for chunk numbers of boundaries with vertices
32433  // for non deletion
32434  Vector<unsigned> chunk_for_non_deletion;
32435 
32436  // The number of vertices for nondeletion in the shared
32437  // boundaries
32438  Vector<unsigned> number_vertices_non_deletion;
32439 
32440  // Vertices marked for nondeletion in shared boundaries
32441  Vector<Vector<Vector<double> > > vertices_for_non_deletion;
32442 
32443  // Get the boundary ids of the shared boundaries with jproc
32444  // processor
32445  Vector<unsigned> shd_bnd_ids =
32446  this->shared_boundaries_ids(my_rank, jproc);
32447 
32448  // Get the number of shared boundaries with jproc
32449  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32450  // loop over the shared boundaries with jproc
32451  for (unsigned ishd_bnd=0;ishd_bnd<n_shd_bnd_jproc;ishd_bnd++)
32452  {
32453  // Get the shared boudary id
32454  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32455  // Get the associated polyline
32456  TriangleMeshPolyLine *shd_polyline_pt =
32457  this->boundary_polyline_pt(shd_bnd_id);
32458  // Get the chunk number
32459  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32460 
32461  // Store the vertices not allowed for deletion
32462  std::set<Vector<double> > no_delete_vertex;
32463 
32464  // Does the boundary has vertives for nondeleteion?
32465  const bool boundary_receive_connections =
32466  this->boundary_connections(shd_bnd_id, chunk,
32467  no_delete_vertex);
32468 
32469  // Get the number of vertices for nondeletion
32470  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32471 
32472  // Are there vertices for nondeletion?
32473  if (boundary_receive_connections && n_non_delete_vertex > 0)
32474  {
32475  // Add the shared boundary id
32476  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32477  // Add the chunk number
32478  chunk_for_non_deletion.push_back(chunk);
32479  // Add the number of vertices for non deletion
32480  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32481 
32482  // The list of vertices to add
32483  Vector<Vector<double> > tmp_vertices;
32484 
32485  // Add the vertices for non deletion
32486  for (std::set<Vector<double> >::iterator it =
32487  no_delete_vertex.begin();
32488  it != no_delete_vertex.end(); it++)
32489  {
32490  // Get the vertex coordinate
32491  Vector<double> vertex = (*it);
32492  tmp_vertices.push_back(vertex);
32493  }
32494 
32495  // Add the vertices coordinates to a vector storage
32496  vertices_for_non_deletion.push_back(tmp_vertices);
32497 
32498  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32499 
32500  } // for (ishd_bnd<n_shd_bnd_jproc)
32501 
32502  // ----------------------------------------------------------
32503  // ----------------------------------------------------------
32504  // ----------------------------------------------------------
32505  // Now send the info. to the other processor (jproc)
32506  // ----------------------------------------------------------
32507  // ----------------------------------------------------------
32508  // ----------------------------------------------------------
32509  // Get the communicator of the mesh
32510  OomphCommunicator* comm_pt = this->communicator_pt();
32511 
32512  // Set MPI info
32513  MPI_Status status;
32514  MPI_Request request;
32515 
32516  // -----------------------------------------------------------
32517  // Prepare the data
32518  // Get the number of shared boundaires with vertices marked
32519  // for non deletion
32520  const unsigned n_shd_bnd_with_non_delete_vertices =
32521  shd_bnd_id_for_non_deletion.size();
32522 
32523  // Size of the package
32524  const unsigned size_package = 3;
32525  // Ndata to send
32526  const unsigned n_unsigned_data_to_send =
32527  n_shd_bnd_with_non_delete_vertices*size_package;
32528  // The flat package to send the info.
32529  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32530  Vector<double> flat_package_double_send;
32531 
32532  Vector<unsigned> flat_package_unsigned_recv;
32533  Vector<double> flat_package_double_recv;
32534 
32535  // Prepare the data to be sent
32536  unsigned j=0;
32537  for (unsigned i=0;i<n_shd_bnd_with_non_delete_vertices;i++)
32538  {
32539  // The shared boundary id
32540  flat_package_unsigned_send[j++] =
32541  shd_bnd_id_for_non_deletion[i];
32542  // The chunk number
32543  flat_package_unsigned_send[j++] =
32544  chunk_for_non_deletion[i];
32545  // The number of vertices for nondeletion
32546  flat_package_unsigned_send[j++] =
32547  number_vertices_non_deletion[i];
32548  // Also package the vertices
32549  const unsigned n_vertices_non_deletion =
32550  number_vertices_non_deletion[i];
32551  // Loop over the vertices and store them in the flat
32552  // package to be sent
32553  for (unsigned h=0;h<n_vertices_non_deletion;h++)
32554  {
32555  flat_package_double_send.push_back(
32556  vertices_for_non_deletion[i][h][0]);
32557  flat_package_double_send.push_back(
32558  vertices_for_non_deletion[i][h][1]);
32559  } // for (h<n_vertices_non_deletion)
32560 
32561  } // for (i<n_shd_bnd_with_non_delete_vertices)
32562 
32563  // ----------------------------------------------------------
32564  int send_proc = jproc;
32565  int recv_proc = jproc;
32566  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32567  unsigned send_count_double_values = flat_package_double_send.size();
32568  //-----------------------------------------------------------
32569  // Do the transfering of info.
32570  //-----------------------------------------------------------
32571  // Start with UNSIGNED info.
32572  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
32573  send_proc,1,comm_pt->mpi_comm(),&request);
32574 
32575  unsigned receive_count_unsigned_values=0;
32576  MPI_Recv(&receive_count_unsigned_values,1,MPI_UNSIGNED,
32577  recv_proc,1,comm_pt->mpi_comm(),&status);
32578 
32579  MPI_Wait(&request,MPI_STATUS_IGNORE);
32580 
32581  // Send the actual data
32582  if (send_count_unsigned_values!=0)
32583  {
32584  MPI_Isend(&flat_package_unsigned_send[0],
32585  send_count_unsigned_values,MPI_UNSIGNED,
32586  send_proc,2,comm_pt->mpi_comm(),&request);
32587  }
32588 
32589  // Receive the actual data
32590  if (receive_count_unsigned_values!=0)
32591  {
32592  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32593  MPI_Recv(&flat_package_unsigned_recv[0],
32594  receive_count_unsigned_values,
32595  MPI_UNSIGNED,recv_proc,2,comm_pt->mpi_comm(),&status);
32596  }
32597 
32598  // Wait for sending the data and the other processor
32599  // receives
32600  if (send_count_unsigned_values!=0)
32601  {
32602  MPI_Wait(&request,MPI_STATUS_IGNORE);
32603  }
32604 
32605  //-----------------------------------------------------------
32606  // Then continue with DOUBLE info.
32607  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
32608  send_proc,1,comm_pt->mpi_comm(),&request);
32609 
32610  unsigned receive_count_double_values=0;
32611  MPI_Recv(&receive_count_double_values,1,MPI_UNSIGNED,
32612  recv_proc,1,comm_pt->mpi_comm(),&status);
32613 
32614  MPI_Wait(&request,MPI_STATUS_IGNORE);
32615 
32616  // Send the actual data
32617  if (send_count_double_values!=0)
32618  {
32619  MPI_Isend(&flat_package_double_send[0],
32620  send_count_double_values,MPI_DOUBLE,
32621  send_proc,2,comm_pt->mpi_comm(),&request);
32622  }
32623 
32624  // Receive the actual data
32625  if (receive_count_double_values!=0)
32626  {
32627  flat_package_double_recv.resize(receive_count_double_values);
32628  MPI_Recv(&flat_package_double_recv[0],
32629  receive_count_double_values,
32630  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
32631  }
32632 
32633  // Wait for sending the data and the other processor
32634  // receives
32635  if (send_count_double_values!=0)
32636  {
32637  MPI_Wait(&request,MPI_STATUS_IGNORE);
32638  }
32639 
32640  // ------------------------------------------------------------
32641  // ------------------------------------------------------------
32642  // ------------------------------------------------------------
32643  // Now unpackage the data
32644  // ------------------------------------------------------------
32645  // ------------------------------------------------------------
32646  // ------------------------------------------------------------
32647 
32648  // Storage for the boundaries ids with vertices for non
32649  // deletion
32650  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32651 
32652  // Storage for chunk numbers of boundaries with vertices
32653  // for non deletion
32654  Vector<unsigned> recv_chunk_for_non_deletion;
32655 
32656  // The number of vertices for nondeletion in the shared
32657  // boundaries
32658  Vector<unsigned> recv_number_vertices_non_deletion;
32659 
32660  // Vertices marked for nondeletion in shared boundaries
32661  Vector<Vector<Vector<double> > > recv_vertices_for_non_deletion;
32662 
32663  // Counter
32664  j = 0;
32665  for (unsigned i=0;i<receive_count_unsigned_values;i+=3)
32666  {
32667  // Get the shared boundary id
32668  const unsigned recv_shd_bnd_id =
32669  flat_package_unsigned_recv[i];
32670  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32671  // Get the chunk number
32672  const unsigned recv_chunk =
32673  flat_package_unsigned_recv[i+1];
32674  recv_chunk_for_non_deletion.push_back(recv_chunk);
32675  // Get the number of vertices for non deletion
32676  const unsigned recv_num_vertices =
32677  flat_package_unsigned_recv[i+2];
32678  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32679 
32680  // Create a temporal storage
32681  Vector<Vector<double> > temp_recv_vertices;
32682  // Now get the vertices
32683  for (unsigned h=0;h<recv_num_vertices;h++)
32684  {
32685  Vector<double> tmp_vertex(2);
32686  tmp_vertex[0] = flat_package_double_recv[j++];
32687  tmp_vertex[1] = flat_package_double_recv[j++];
32688  // Add the vertex to the vector of vertices
32689  temp_recv_vertices.push_back(tmp_vertex);
32690  } // for (h<recv_num_vertices)
32691 
32692  // Add the vertices to the vector of vertices
32693  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32694 
32695  } // for(i<receive_count_unsigned_values)
32696 
32697  // ---------------------------------------------------------
32698  // ---------------------------------------------------------
32699  // ---------------------------------------------------------
32700  // Now add the vertices to the data structures to mark them
32701  // as non delete-able
32702  // ---------------------------------------------------------
32703  // ---------------------------------------------------------
32704  // ---------------------------------------------------------
32705 
32706  // Get the number of shd boundaries that have vertices
32707  // marked for non deletion
32708  const unsigned n_recv_shd_bnd_id_for_non_deletion =
32709  recv_shd_bnd_id_for_non_deletion.size();
32710  // loop over the shared boundaries and add the data for non
32711  // deletion
32712  for (unsigned i=0;i<n_recv_shd_bnd_id_for_non_deletion;i++)
32713  {
32714  // Get the shared boundary id.
32715  const unsigned shd_bnd_id =
32716  recv_shd_bnd_id_for_non_deletion[i];
32717  // Get the chunk number
32718  unsigned chunk = recv_chunk_for_non_deletion[i];
32719  // Increase and decrease the chunk number to avoid the
32720  // warning when compiling without PARANOID
32721  chunk++;
32722  chunk--;
32723 
32724  // Get the number of vertices marked for non deletion
32725  const unsigned n_vertices =
32726  recv_number_vertices_non_deletion[i];
32727  // Add all the vertices
32728  for (unsigned h=0;h<n_vertices;h++)
32729  {
32730  // Get the vertex
32731  Vector<double> vertex(2);
32732  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
32733  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
32734  // Add the vertex to the data structure for non
32735  // deletion
32736  //Boundary_chunk_connections_pt[shd_bnd_id][chunk].
32737  // insert(vertex);
32738  Boundary_connections_pt[shd_bnd_id].insert(vertex);
32739 
32740  } // for (h<n_vertices)
32741 
32742  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
32743 
32744  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
32745 
32746  } // for (jproc < nproc)
32747 
32748  }
32749 #endif // #ifdef OOMPH_HAS_MPI
32750 
32751  //=========================================================================
32752  /// \short After unrefinement and refinement has taken place compute
32753  /// the new vertices numbers of the temporary representation of the
32754  // boundaries to connect.
32755  //=========================================================================
32756  template<class ELEMENT>
32758  Vector<TriangleMeshPolygon *> &tmp_outer_polygons_pt,
32759  Vector<TriangleMeshOpenCurve *> &tmp_open_curves_pt)
32760  {
32761  // Dummy storages
32762  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
32763  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
32764 
32765  // Clear the storage
32766  dummy_resume_initial_connection_polyline_pt.clear();
32767  dummy_resume_final_connection_polyline_pt.clear();
32768 
32769  // Get the initial shared boundary id (to check whether the
32770  // polylines represent original or shared boundaries)
32771  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32772 
32773  // ------------------------------------------------------------------
32774  // This seems unnecesary since the outer polygons does not create
32775  // connections with other boundaries (the original ones)
32776  // ------------------------------------------------------------------
32777  // Unnecessary?
32778  // ------------------------------------------------------------------
32779 
32780  // Loop over the temporary outer polygons create the connection
32781  // information of those boundaries marked to be connected at their
32782  // ends
32783 
32784  // ------------------------------------------------------------------
32785  // Temporary outer polygons
32786  // ------------------------------------------------------------------
32787 
32788  // Get the number of outer boundaries (closed boundaries)
32789  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
32790 
32791  // Loop over the outer boundaries
32792  for (unsigned i = 0; i < n_outer_boundaries; i++)
32793  {
32794  // Get a temporary polygon representation
32795  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
32796  // Get the number of polylines associated to the current outer
32797  // boundary
32798  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32799  // Loop over the polylines
32800  for (unsigned p = 0; p < n_polyline; p++)
32801  {
32802  // Get a temporary representation of the polyline
32803  TriangleMeshPolyLine* tmp_polyline_pt =
32804  tmp_polygon_pt->polyline_pt(p);
32805 
32806  // Get the boundary id
32807  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32808 
32809  // Is the boundary to connect a shared boundary
32810  if (bnd_id < init_shd_bnd_id)
32811  {
32812  // Restore the connections of the current polyline
32813  restore_polyline_connections_helper(
32814  tmp_polyline_pt,
32815  dummy_resume_initial_connection_polyline_pt,
32816  dummy_resume_final_connection_polyline_pt);
32817 
32818  } // if (bnd_id < init_shd_bnd_id)
32819 
32820  } // for (p < n_polyline)
32821 
32822  } // for (i < n_outer_boundaries)
32823 
32824  // ------------------------------------------------------------------
32825  // Unnecessary?
32826  // ------------------------------------------------------------------
32827 
32828  // ------------------------------------------------------------------
32829  // Temporary open boundaries (nonclosed internal boundaries)
32830  // ------------------------------------------------------------------
32831 
32832  // Get the number of internal boundaries (open boundaries)
32833  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
32834 
32835  // Loop over the internal open boundaries
32836  for (unsigned i = 0; i < n_open_boundaries; i++)
32837  {
32838  // Get a temporary representation for the open curve
32839  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
32840 
32841  // Get the number of curve sections associated to the current
32842  // internal open boundary
32843  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32844 
32845  // Loop over the curve section
32846  for (unsigned p = 0; p < n_curve_section; p++)
32847  {
32848  // Get a temporary representation of the curve section
32849  // (polyline)
32850  TriangleMeshPolyLine* tmp_polyline_pt =
32851  tmp_open_curve_pt->polyline_pt(p);
32852 
32853  // Get the boundary id
32854  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32855 
32856  // Is the boundary to connect a shared boundary
32857  if (bnd_id < init_shd_bnd_id)
32858  {
32859  // Restore the connections of the current polyline
32860  restore_polyline_connections_helper(
32861  tmp_polyline_pt,
32862  dummy_resume_initial_connection_polyline_pt,
32863  dummy_resume_final_connection_polyline_pt);
32864 
32865  } // if (bnd_id < init_shd_bnd_id)
32866 
32867  } // for (p < n_curve_section)
32868 
32869  } // for (i < n_open_boundaries)
32870 
32871  }
32872 
32873  //=========================================================================
32874  /// \short After unrefinement and refinement has taken place compute
32875  /// the new vertices numbers of the boundaries to connect (in a
32876  /// distributed scheme it may be possible that the destination
32877  /// boundary does no longer exist, therefore the connection is
32878  /// suspended. It is not permanently deleted because if load balance
32879  /// takes place it may be possible that the boundary to connect be
32880  /// part of the new domain representation, so the connection would
32881  /// exist)
32882  //=========================================================================
32883  template<class ELEMENT>
32885  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
32886  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
32887  {
32888  // Clear the storage
32889  resume_initial_connection_polyline_pt.clear();
32890  resume_final_connection_polyline_pt.clear();
32891 
32892  // Loop over the boundaries in the domain (outer, internal -- closed
32893  // and open) and restore the connection information of those
32894  // boundaries marked to be connected at their ends
32895 
32896  // ------------------------------------------------------------------
32897  // Outer boundaries
32898  // ------------------------------------------------------------------
32899 
32900  // Get the number of outer boundaries (closed boundaries)
32901  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
32902 
32903  // Loop over the outer boundaries
32904  for (unsigned i = 0; i < n_outer_boundaries; i++)
32905  {
32906  // Get a temporary polygon representation
32907  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32908  // Get the number of polylines associated to the current outer
32909  // boundary
32910  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32911  // Loop over the polylines
32912  for (unsigned p = 0; p < n_polyline; p++)
32913  {
32914  // Get a temporary representation of the polyline
32915  TriangleMeshPolyLine* tmp_polyline_pt =
32916  tmp_polygon_pt->polyline_pt(p);
32917 
32918  // Restore the connections of the current polyline
32919  restore_polyline_connections_helper(
32920  tmp_polyline_pt,
32921  resume_initial_connection_polyline_pt,
32922  resume_final_connection_polyline_pt);
32923 
32924  } // for (p < n_polyline)
32925 
32926  } // for (i < n_outer_boundaries)
32927 
32928  // ------------------------------------------------------------------
32929  // Internal boundaries
32930  // ------------------------------------------------------------------
32931 
32932  // Get the number of internal boundaries (closed boundaries)
32933  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
32934 
32935  // Loop over the internal boundaries
32936  for (unsigned i = 0; i < n_internal_boundaries; i++)
32937  {
32938  // Get a temporary polygon representation
32939  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32940  // Get the number of polylines associated to the current internal
32941  // boundary
32942  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32943  // Loop over the polylines
32944  for (unsigned p = 0; p < n_polyline; p++)
32945  {
32946  // Get a temporary representation of the polyline
32947  TriangleMeshPolyLine* tmp_polyline_pt =
32948  tmp_polygon_pt->polyline_pt(p);
32949 
32950  // Restore the connections of the current polyline
32951  restore_polyline_connections_helper(
32952  tmp_polyline_pt,
32953  resume_initial_connection_polyline_pt,
32954  resume_final_connection_polyline_pt);
32955 
32956  } // for (p < n_polyline)
32957 
32958  } // for (i < n_internal_boundaries)
32959 
32960  // ------------------------------------------------------------------
32961  // Open boundaries (nonclosed internal boundaries)
32962  // ------------------------------------------------------------------
32963 
32964  // Get the number of internal boundaries (open boundaries)
32965  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32966 
32967  // Loop over the internal open boundaries
32968  for (unsigned i = 0; i < n_open_boundaries; i++)
32969  {
32970  // Get a temporary representation for the open curve
32971  TriangleMeshOpenCurve* tmp_open_curve_pt =
32972  this->Internal_open_curve_pt[i];
32973 
32974  // Get the number of curve sections associated to the current
32975  // internal open boundary
32976  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32977 
32978  // Loop over the curve section
32979  for (unsigned p = 0; p < n_curve_section; p++)
32980  {
32981  // Get a temporary representation of the curve section
32982  // (polyline)
32983  TriangleMeshPolyLine* tmp_polyline_pt =
32984  tmp_open_curve_pt->polyline_pt(p);
32985 
32986  // Restore the connections of the current polyline
32987  restore_polyline_connections_helper(
32988  tmp_polyline_pt,
32989  resume_initial_connection_polyline_pt,
32990  resume_final_connection_polyline_pt);
32991 
32992  } // for (p < n_curve_section)
32993 
32994  } // for (i < n_open_boundaries)
32995 
32996  }
32997 
32998  //=========================================================================
32999  /// \short Restore the connections of the specific polyline
33000  /// The vertices numbering on the destination boundaries may have
33001  /// change because of (un)refinement in the destination boundaries.
33002  /// Also deals with connection that do not longer exist because the
33003  /// destination boundary does no longer exist because of the distribution
33004  /// process
33005  //=========================================================================
33006  template<class ELEMENT>
33009  TriangleMeshPolyLine* polyline_pt,
33010  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33011  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33012  {
33013  // If the polyline is connected at any of its ends compute the new
33014  // vertex number on the destination boundary
33015 
33016  // ------------------------------------------------------------------
33017  // Is the initial vertex connected?
33018  if (polyline_pt->is_initial_vertex_connected())
33019  {
33020  // The pointer to the boundary to connect
33021  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33022 
33023  // Get the boundary id of the destination/connected boundary
33024  const unsigned dst_bnd_id_initial =
33025  polyline_pt->initial_vertex_connected_bnd_id();
33026 
33027  // Get the initial vertex on the current boundary
33028  Vector<double> src_vertex_coordinates_initial =
33029  polyline_pt->vertex_coordinate(0);
33030 
33031 #ifdef PARANOID
33032  // Is the mesh distributed?
33033 #ifdef OOMPH_HAS_MPI
33034  if (this->is_mesh_distributed())
33035  {
33036  // Get the initial shared boundary id
33037  const unsigned init_shd_bnd_id =
33038  this->initial_shared_boundary_id();
33039  // Is the boundary to connect a shared boundary
33040  if (dst_bnd_id_initial >= init_shd_bnd_id)
33041  {
33042  // Get the current polyline original boundary id
33043  const unsigned bnd_id = polyline_pt->boundary_id();
33044  std::ostringstream error_message;
33045  error_message
33046  << "INITIAL VERTEX CONNECTION\n"
33047  << "The current original boundary is trying to connect to a\n"
33048  << "shared boundary, this is not allowed. In this case the\n"
33049  << "shared boundary should be the one that connects with the\n"
33050  << "original boundary\n"
33051  << "The current original boundary (" << bnd_id << ") is marked\n"
33052  << "to have a connection at the\nINITIAL vertex ("
33053  << src_vertex_coordinates_initial[0] << ","
33054  << src_vertex_coordinates_initial[1] << ")\n"
33055  << "with the shared boundary ("<< dst_bnd_id_initial << ")\n"
33056  << "This is the list of vertices on the shared destination boundary\n";
33057  // Get the pointer to the associated polyline by using the
33058  // boundary id
33059  TriangleMeshPolyLine *dst_polyline =
33060  this->boundary_polyline_pt(dst_bnd_id_initial);
33061  // The number of vertices on the destination boundary
33062  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33063  // Loop over the vertices print them
33064  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33065  {
33066  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33067  error_message
33068  << "Vertex#(i): ("
33069  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33070  }
33071  throw OomphLibError(
33072  error_message.str(),
33073  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33074  OOMPH_EXCEPTION_LOCATION);
33075  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33076 
33077  } // if (this->is_mesh_distributed())
33078 #endif // #ifdef OOMPH_HAS_MPI
33079 
33080 #endif // #ifdef PARANOID
33081 
33082  // Flag to indicate if the vertex was found on the destination
33083  // boundary
33084  bool found_vertex_on_dst_boundary_initial = false;
33085 
33086  // Flag that stores the chunk number to connect (only used in
33087  // distributed meshes)
33088  unsigned sub_poly_to_connect = 0;
33089 
33090  // Store the vertex number on the destination boundary
33091  unsigned n_vertex_connection_initial = 0;
33092 
33093  // Flags only used in a distributed mesh
33094  // ----------------------------------------
33095  // Flag to indicate we are trying to connect to an split boundary
33096  bool connecting_to_an_split_boundary = false;
33097 
33098  // Flag to indicate we are trying to connecto to an internal
33099  // boundary that is overlaped by a shared boundary)
33100  bool connecting_to_an_overlaped_boundary = false;
33101 
33102 #ifdef OOMPH_HAS_MPI
33103  if (this->is_mesh_distributed())
33104  {
33105  // We can only connect to an original boundary, check if the
33106  // boundary was splitted during the distribution process to
33107  // consider all the chunks (sub-polylines) of the boundary
33108  if (this->boundary_was_splitted(dst_bnd_id_initial))
33109  {
33110  connecting_to_an_split_boundary = true;
33111  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33112 
33113  // Check if the destination boundary, or any of its chunks is
33114  // marked to be overlapped by a shared boundary, if that is the
33115  // case we can only connect to the chunks that are not
33116  // overlapped by shared boundaries (the shared boundaries are in
33117  // charge of generating the connections with original boundaries
33118  // and with themselves)
33119  if (connecting_to_an_split_boundary)
33120  {
33121  // Get the number of chucks that represent the destination
33122  // boundary
33123  const unsigned n_sub_poly =
33124  this->nboundary_subpolylines(dst_bnd_id_initial);
33125  // Now loop over the chunks of the destination boundary and if
33126  // any of them is marked to be overlaped by a shared boundary
33127  // then set the flag and break the loop
33128  for (unsigned ii =0; ii < n_sub_poly; ii++)
33129  {
33130  if (this->
33131  boundary_marked_as_shared_boundary(dst_bnd_id_initial, ii))
33132  {
33133  // Mark the boundary as being overlaped by a shared
33134  // boundary
33135  connecting_to_an_overlaped_boundary = true;
33136  // Break, no need to look for more overlapings
33137  break;
33138  } // if (boundary_marked_as_shared_boundary(...))
33139  } // for (ii < n_sub_poly)
33140  } // if (connecting_to_an_split_boundary)
33141  else
33142  {
33143  // If not connecting to an split boundary then check if the
33144  // whole destination boundary is overlaped by an internal
33145  // boundary
33146  if (this->
33147  boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33148  {
33149  // Mark the boundary as being overlaped by a shared boundary
33150  connecting_to_an_overlaped_boundary = true;
33151  } // if (boundary_marked_as_shared_boundary(...))
33152  } // else if (connecting_to_an_split_boundary)
33153 
33154  } // if (this->is_mesh_distributed())
33155 
33156 #endif // #ifdef OOMPH_HAS_MPI
33157 
33158  // If we are connecting neither to an split boundary nor an
33159  // overlaped boundary then get the pointer to the original
33160  // boundary
33161  if (!(connecting_to_an_split_boundary ||
33162  connecting_to_an_overlaped_boundary))
33163  {
33164  // Get the polyline pointer representing the destination
33165  // boundary
33166  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33167  } // else if (NOT split, NOT overlaped)
33168 
33169  // Now look for the vertex number on the destination boundary(ies)
33170  // -- in case that the boundary was split ---
33171 
33172  // Do not check for same orientation, that was previously worked
33173  // by interchanging the connections boundaries (if necessary)
33174 
33175  // If the boundary was not split then ...
33176  if (!connecting_to_an_split_boundary)
33177  {
33178  // ... check if the boundary is marked to be overlaped by
33179  // a shared boundary
33180  if (!connecting_to_an_overlaped_boundary)
33181  {
33182  // If that is not the case then we can safely look for the
33183  // vertex number on the destination boundary
33184  found_vertex_on_dst_boundary_initial =
33185  this->get_connected_vertex_number_on_destination_polyline(
33186  poly_to_connect_pt,
33187  src_vertex_coordinates_initial,
33188  n_vertex_connection_initial);
33189 
33190  } // if (!connecting_to_an_overlaped_boundary)
33191  else
33192  {
33193  // If the whole boundary is marked to be overlaped by a shared
33194  // boundary then do nothing, the shared boundaries are already
33195  // in charge of performing the connection (it will be required
33196  // to disabled the connection) with the original boundary
33197 
33198  } // else if (!connecting_to_an_overlaped_boundary)
33199 
33200  } // if (!connecting_to_an_split_boundary)
33201 #ifdef OOMPH_HAS_MPI
33202  else
33203  {
33204  // If the boundary was split then we need to look for the vertex
33205  // in the sub-polylines
33206 
33207  // Get the sub-polylines vector
33208  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33209  this->boundary_subpolylines(dst_bnd_id_initial);
33210 
33211  // Get the number of sub-polylines
33212  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33213 #ifdef PARANOID
33214  if (nsub_poly <= 1)
33215  {
33216  std::ostringstream error_message;
33217  error_message
33218  <<"The boundary (" << dst_bnd_id_initial << ") was "
33219  << "marked to be splitted but\n"
33220  << "there are only ("<<nsub_poly<<") polylines to "
33221  << "represent it.\n";
33222  throw OomphLibError(
33223  error_message.str(),
33224  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33225  OOMPH_EXCEPTION_LOCATION);
33226  } // if (nsub_poly <= 1)
33227 #endif
33228  // We need to check if the boundary is marked to be overlaped by
33229  // a shared boundary, if that is the case we need to check for
33230  // each indivual subpolyline, and for those overlaped by a
33231  // shared polyline do nothing, the shared polylines have already
33232  // deal with these connections
33233 
33234  // ... check if the boundary is marked to be overlaped by
33235  // a shared boundary
33236  if (!connecting_to_an_overlaped_boundary)
33237  {
33238  // The boundary is not overlapped by shared boundaries, we can
33239  // work without checking the subpolylines individually (non of
33240  // them are overlapped by a shared boundary)
33241 
33242  // Look for the vertex number to connect on each of the
33243  // subpolyines
33244  for (unsigned isub = 0; isub < nsub_poly; isub++)
33245  {
33246  // Assign the pointer to the sub-polyline
33247  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33248  // Search for the vertex in the current sub-polyline
33249  found_vertex_on_dst_boundary_initial =
33250  this->get_connected_vertex_number_on_destination_polyline(
33251  poly_to_connect_pt,
33252  src_vertex_coordinates_initial,
33253  n_vertex_connection_initial);
33254 
33255  // If we have found the vertex to connect then break the
33256  // loop
33257  if (found_vertex_on_dst_boundary_initial)
33258  {
33259  // But first save the subpoly number (chunk), that will be
33260  // used to perform the connection
33261  sub_poly_to_connect = isub;
33262  break;
33263  } // if (found_vertex_on_dst_boundary_initial)
33264 
33265  } // for (isub < nsub_poly)
33266 
33267  } // if (!connecting_to_an_overlaped_boundary)
33268  else
33269  {
33270  // If connecting to an overlapped boundary then we ignore the
33271  // subpolylines overlapped by shared boundaries and only look
33272  // on the sub-polylines that are not marked as being overlaped
33273  // by shared boundaries
33274 
33275  // Look for the vertex number to connect on each of the
33276  // subpolyines
33277  for (unsigned isub = 0; isub < nsub_poly; isub++)
33278  {
33279  // Only work with those sub-polylines that are not overlaped
33280  // by shared boundaries
33281  if (!this->
33282  boundary_marked_as_shared_boundary(dst_bnd_id_initial, isub))
33283  {
33284  // Assign the pointer to the sub-polyline
33285  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33286 
33287  // Search for the vertex in the current sub-polyline
33288  found_vertex_on_dst_boundary_initial =
33289  this->get_connected_vertex_number_on_destination_polyline(
33290  poly_to_connect_pt,
33291  src_vertex_coordinates_initial,
33292  n_vertex_connection_initial);
33293 
33294  // Was the vertex found?
33295  if (found_vertex_on_dst_boundary_initial)
33296  {
33297  // But first save the subpoly number (chunk), that will
33298  // be used to perform the connection
33299  sub_poly_to_connect = isub;
33300  break;
33301  } // if (found_vertex_on_dst_boundary_initial)
33302 
33303  } // if (not overlaped by shared boundary)
33304 
33305  } // for (isub < nsub_poly)
33306 
33307  } // else if (!connecting_to_an_overlaped_boundary)
33308 
33309  } // else if (!connecting_to_an_split_boundary)
33310 #endif // #ifdef OOMPH_HAS_MPI
33311 
33312  // If not found it may be that the connection information is
33313  // inverted
33314  if (!found_vertex_on_dst_boundary_initial)
33315  {
33316  // Is the mesh distributed?
33317 #ifdef OOMPH_HAS_MPI
33318  if (this->is_mesh_distributed())
33319  {
33320  // If the mesh is distributed and the vertex number was not
33321  // found, that means that the boundary (or vertex) to connect
33322  // in the destination boundary is not in the current
33323  // processor. In that case suspend the connection
33324  polyline_pt->suspend_initial_vertex_connected();
33325  // Add the polyline to the vector of polylines whose
33326  // connection will be resumed at the end of the adaptation
33327  // process
33328  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33329  // The shared boundaries are marked to connect to the initial
33330  // vertex of the polyline (remember that a shared boundary
33331  // stops adding nodes when it finds a node on an original
33332  // boundary) -- The initial vertex is now a base node
33333  }
33334  else
33335 #endif // #ifdef OOMPH_HAS_MPI
33336  {
33337 #ifdef PARANOID
33338  // If not found then there is a problem with the vertices
33339  // Get the associated boundary id of the current polyline
33340  const unsigned bnd_id = polyline_pt->boundary_id();
33341  std::ostringstream error_message;
33342  error_message
33343  << "INITIAL VERTEX CONNECTION\n"
33344  << "It was not possible to find the associated "
33345  << "vertex number on the destination boundary\n"
33346  << "The current boundary (" << bnd_id << ") is marked to have"
33347  << "a connection at the\nINITIAL vertex ("
33348  << src_vertex_coordinates_initial[0] << ","
33349  << src_vertex_coordinates_initial[1] << ")\n"
33350  << "with boundary ("<< dst_bnd_id_initial << ")\n"
33351  << "This is the list of vertices on the destination boundary\n";
33352  // Get the pointer to the associated polyline by using the
33353  // boundary id
33354  TriangleMeshPolyLine *dst_polyline =
33355  this->boundary_polyline_pt(dst_bnd_id_initial);
33356  // The number of vertices on the destination boundary
33357  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33358  // Loop over the vertices print them
33359  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33360  {
33361  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33362  error_message
33363  << "Vertex#(i): ("
33364  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33365  }
33366  throw OomphLibError(
33367  error_message.str(),
33368  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33369  OOMPH_EXCEPTION_LOCATION);
33370 #endif
33371 
33372  } // else if (this->is_mesh_distributed())
33373 
33374  } // if (!found_vertex_on_dst_boundary_initial)
33375  else
33376  {
33377  // Set the vertex number on the destination boundary
33378  polyline_pt->initial_vertex_connected_n_vertex() =
33379  n_vertex_connection_initial;
33380 
33381  // Set the chunk number on the destination boundary
33382  polyline_pt->initial_vertex_connected_n_chunk() =
33383  sub_poly_to_connect;
33384 
33385  } // else if (!found_vertex_on_dst_boundary_initial)
33386 
33387  } // if (polyline_pt->is_initial_vertex_connected())
33388 
33389  // ------------------------------------------------------------------
33390  // Is the final vertex connected?
33391  if (polyline_pt->is_final_vertex_connected())
33392  {
33393  // The pointer to the boundary to connect
33394  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33395 
33396  // Get the boundary id of the destination/connected boundary
33397  const unsigned dst_bnd_id_final =
33398  polyline_pt->final_vertex_connected_bnd_id();
33399 
33400  // Get the final vertex on the current boundary
33401  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33402  Vector<double> src_vertex_coordinates_final =
33403  polyline_pt->vertex_coordinate(tmp_n_vertices-1);
33404 
33405 
33406 #ifdef PARANOID
33407  // Is the mesh distributed?
33408 #ifdef OOMPH_HAS_MPI
33409  if (this->is_mesh_distributed())
33410  {
33411  // Get the initial shared boundary id
33412  const unsigned init_shd_bnd_id =
33413  this->initial_shared_boundary_id();
33414  // Is the boundary to connect a shared boundary
33415  if (dst_bnd_id_final >= init_shd_bnd_id)
33416  {
33417  // Get the current polyline original boundary id
33418  const unsigned bnd_id = polyline_pt->boundary_id();
33419  std::ostringstream error_message;
33420  error_message
33421  << "FINAL VERTEX CONNECTION\n"
33422  << "The current original boundary is trying to connect to a\n"
33423  << "shared boundary, this is not allowed. In this case the\n"
33424  << "shared boundary should be the one that connects with the\n"
33425  << "original boundary\n"
33426  << "The current boundary (" << bnd_id << ") is marked to have "
33427  << "a connection at the\nFINAL vertex ("
33428  << src_vertex_coordinates_final[0] << ","
33429  << src_vertex_coordinates_final[1] << ")\n"
33430  << "with boundary ("<< dst_bnd_id_final << ")\n"
33431  << "This is the list of vertices on the destination boundary\n";
33432  // Get the pointer to the associated polyline by using the
33433  // boundary id
33434  TriangleMeshPolyLine *dst_polyline =
33435  this->boundary_polyline_pt(dst_bnd_id_final);
33436  // The number of vertices on the destination boundary
33437  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33438  // Loop over the vertices print them
33439  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33440  {
33441  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33442  error_message
33443  << "Vertex#("<<i<<"): ("
33444  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33445  }
33446  throw OomphLibError(
33447  error_message.str(),
33448  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33449  OOMPH_EXCEPTION_LOCATION);
33450  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33451 
33452  } // if (this->is_mesh_distributed())
33453 #endif // #ifdef OOMPH_HAS_MPI
33454 
33455 #endif // #ifdef PARANOID
33456 
33457  // Flag to indicate if the vertex was found on the destination
33458  // boundary
33459  bool found_vertex_on_dst_boundary_final = false;
33460 
33461  // Flag that stores the chunk number to connect (only used in
33462  // distributed meshes)
33463  unsigned sub_poly_to_connect = 0;
33464 
33465  // Store the vertex number on the destination boundary
33466  unsigned n_vertex_connection_final = 0;
33467 
33468  // Flags only used in a distributed mesh
33469  // ----------------------------------------
33470  // Flag to indicate we are trying to connect to an split boundary
33471  bool connecting_to_an_split_boundary = false;
33472 
33473  // Flag to indicate we are trying to connecto to an internal
33474  // boundary that is overlaped by a shared boundary)
33475  bool connecting_to_an_overlaped_boundary = false;
33476 
33477 #ifdef OOMPH_HAS_MPI
33478  if (this->is_mesh_distributed())
33479  {
33480  // We can only connect to an original boundary, check if the
33481  // boundary was splitted during the distribution process to
33482  // consider all the chunks (sub-polylines) of the boundary
33483  if (this->boundary_was_splitted(dst_bnd_id_final))
33484  {
33485  connecting_to_an_split_boundary = true;
33486  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33487 
33488  // Check if the destination boundary, or any of its chunks is
33489  // marked to be overlapped by a shared boundary, if that is the
33490  // case we can only connect to the chunks that are not
33491  // overlapped by shared boundaries (the shared boundaries are in
33492  // charge of generating the connections with original boundaries
33493  // and with themselves)
33494  if (connecting_to_an_split_boundary)
33495  {
33496  // Get the number of chucks that represent the destination
33497  // boundary
33498  const unsigned n_sub_poly =
33499  this->nboundary_subpolylines(dst_bnd_id_final);
33500  // Now loop over the chunks of the destination boundary and if
33501  // any of them is marked to be overlaped by a shared boundary
33502  // then set the flag and break the loop
33503  for (unsigned ii =0; ii < n_sub_poly; ii++)
33504  {
33505  if (this->
33506  boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33507  {
33508  // Mark the boundary as being overlaped by a shared
33509  // boundary
33510  connecting_to_an_overlaped_boundary = true;
33511  // Break, no need to look for more overlapings
33512  break;
33513  } // if (boundary_marked_as_shared_boundary(...))
33514  } // for (ii < n_sub_poly)
33515  } // if (connecting_to_an_split_boundary)
33516  else
33517  {
33518  // If not connecting to an split boundary then check if the
33519  // whole destination boundary is overlaped by an internal
33520  // boundary
33521  if (this->
33522  boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33523  {
33524  // Mark the boundary as being overlaped by a shared boundary
33525  connecting_to_an_overlaped_boundary = true;
33526  } // if (boundary_marked_as_shared_boundary(...))
33527  } // else if (connecting_to_an_split_boundary)
33528 
33529  } // if (this->is_mesh_distributed())
33530 
33531 #endif // #ifdef OOMPH_HAS_MPI
33532 
33533  // If we are connecting neither to an split boundary nor an
33534  // overlaped boundary then get the pointer to the original
33535  // boundary
33536  if (!(connecting_to_an_split_boundary ||
33537  connecting_to_an_overlaped_boundary))
33538  {
33539  // Get the polyline pointer representing the destination
33540  // boundary
33541  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33542  } // else if (NOT split, NOT overlaped)
33543 
33544  // Now look for the vertex number on the destination boundary(ies)
33545  // -- in case that the boundary was split ---
33546 
33547  // Do not check for same orientation, that was previously worked
33548  // by interchanging the connections boundaries (if necessary)
33549 
33550  // If the boundary was not split then ...
33551  if (!connecting_to_an_split_boundary)
33552  {
33553  // ... check if the boundary is marked to be overlaped by
33554  // a shared boundary
33555  if (!connecting_to_an_overlaped_boundary)
33556  {
33557  // If that is not the case then we can safely look for the
33558  // vertex number on the destination boundary
33559  found_vertex_on_dst_boundary_final =
33560  this->get_connected_vertex_number_on_destination_polyline(
33561  poly_to_connect_pt,
33562  src_vertex_coordinates_final,
33563  n_vertex_connection_final);
33564 
33565  } // if (!connecting_to_an_overlaped_boundary)
33566  else
33567  {
33568  // If the whole boundary is marked to be overlaped by a shared
33569  // boundary then do nothing, the shared boundaries are already
33570  // in charge of performing the connection (it will be required
33571  // to disabled the connection) with the original boundary
33572 
33573  } // else if (!connecting_to_an_overlaped_boundary)
33574 
33575  } // if (!connecting_to_an_split_boundary)
33576 #ifdef OOMPH_HAS_MPI
33577  else
33578  {
33579  // If the boundary was split then we need to look for the vertex
33580  // in the sub-polylines
33581 
33582  // Get the sub-polylines vector
33583  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33584  this->boundary_subpolylines(dst_bnd_id_final);
33585 
33586  // Get the number of sub-polylines
33587  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33588 #ifdef PARANOID
33589  if (nsub_poly <= 1)
33590  {
33591  std::ostringstream error_message;
33592  error_message
33593  <<"The boundary (" << dst_bnd_id_final << ") was "
33594  << "marked to be splitted but\n"
33595  << "there are only ("<<nsub_poly<<") polylines to "
33596  << "represent it.\n";
33597  throw OomphLibError(
33598  error_message.str(),
33599  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33600  OOMPH_EXCEPTION_LOCATION);
33601  } // if (nsub_poly <= 1)
33602 #endif
33603  // We need to check if the boundary is marked to be overlaped by
33604  // a shared boundary, if that is the case we need to check for
33605  // each indivual subpolyline, and for those overlaped by a
33606  // shared polyline do nothing, the shared polylines have already
33607  // deal with these connections
33608 
33609  // ... check if the boundary is marked to be overlaped by
33610  // a shared boundary
33611  if (!connecting_to_an_overlaped_boundary)
33612  {
33613  // The boundary is not overlapped by shared boundaries, we can
33614  // work without checking the subpolylines individually (non of
33615  // them are overlapped by a shared boundary)
33616 
33617  // Look for the vertex number to connect on each of the
33618  // subpolyines
33619  for (unsigned isub = 0; isub < nsub_poly; isub++)
33620  {
33621  // Assign the pointer to the sub-polyline
33622  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33623  // Search for the vertex in the current sub-polyline
33624  found_vertex_on_dst_boundary_final =
33625  this->get_connected_vertex_number_on_destination_polyline(
33626  poly_to_connect_pt,
33627  src_vertex_coordinates_final,
33628  n_vertex_connection_final);
33629 
33630  // If we have found the vertex to connect then break the
33631  // loop
33632  if (found_vertex_on_dst_boundary_final)
33633  {
33634  // But first save the subpoly number (chunk), that will be
33635  // used to perform the connection
33636  sub_poly_to_connect = isub;
33637  break;
33638  } // if (found_vertex_on_dst_boundary_initial)
33639 
33640  } // for (isub < nsub_poly)
33641 
33642  } // if (!connecting_to_an_overlaped_boundary)
33643  else
33644  {
33645  // If connecting to an overlapped boundary then we ignore the
33646  // subpolylines overlapped by shared boundaries and only look
33647  // on the sub-polylines that are not marked as being overlaped
33648  // by shared boundaries
33649 
33650  // Look for the vertex number to connect on each of the
33651  // subpolyines
33652  for (unsigned isub = 0; isub < nsub_poly; isub++)
33653  {
33654  // Only work with those sub-polylines that are not overlaped
33655  // by shared boundaries
33656  if (!this->
33657  boundary_marked_as_shared_boundary(dst_bnd_id_final, isub))
33658  {
33659  // Assign the pointer to the sub-polyline
33660  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33661 
33662  // Search for the vertex in the current sub-polyline
33663  found_vertex_on_dst_boundary_final =
33664  this->get_connected_vertex_number_on_destination_polyline(
33665  poly_to_connect_pt,
33666  src_vertex_coordinates_final,
33667  n_vertex_connection_final);
33668 
33669  // Was the vertex found?
33670  if (found_vertex_on_dst_boundary_final)
33671  {
33672  // But first save the subpoly number (chunk), that will
33673  // be used to perform the connection
33674  sub_poly_to_connect = isub;
33675  break;
33676  } // if (found_vertex_on_dst_boundary_final)
33677 
33678  } // if (not overlaped by shared boundary)
33679 
33680  } // for (isub < nsub_poly)
33681 
33682  } // else if (!connecting_to_an_overlaped_boundary)
33683 
33684  } // else if (!connecting_to_an_split_boundary)
33685 #endif // #ifdef OOMPH_HAS_MPI
33686 
33687  // If not found it may be that the connection information is
33688  // inverted
33689  if (!found_vertex_on_dst_boundary_final)
33690  {
33691  // Is the mesh distributed?
33692 #ifdef OOMPH_HAS_MPI
33693  if (this->is_mesh_distributed())
33694  {
33695  // If the mesh is distributed and the vertex number was not
33696  // found, that means that the boundary (or vertex) to connect
33697  // in the destination boundary is not in the current
33698  // processor. In that suspend the connection
33699  polyline_pt->suspend_final_vertex_connected();
33700  // Add the polyline to the vector of polylines whose
33701  // connection will be resumed at the end of the adaptation
33702  // process
33703  resume_final_connection_polyline_pt.push_back(polyline_pt);
33704  // The shared boundaries are marked to connect to the final
33705  // vertex of the polyline (remember that a shared boundary
33706  // stops adding nodes when it finds a node on an original
33707  // boundary) -- The final vertex is now a base node
33708  } // if (this->is_mesh_distributed())
33709  else
33710 #endif // #ifdef OOMPH_HAS_MPI
33711  {
33712 #ifdef PARANOID
33713  // If not found then there is a problem with the vertices
33714  // Get the associated boundary id of the current polyline
33715  const unsigned bnd_id = polyline_pt->boundary_id();
33716  std::ostringstream error_message;
33717  error_message
33718  << "FINAL VERTEX CONNECTION\n"
33719  << "It was not possible to find the associated "
33720  << "vertex number on the destination boundary\n"
33721  << "The current boundary (" << bnd_id << ") is marked to have "
33722  << "a connection at the\nFINAL vertex ("
33723  << src_vertex_coordinates_final[0] << ","
33724  << src_vertex_coordinates_final[1] << ")\n"
33725  << "with boundary ("<< dst_bnd_id_final << ")\n"
33726  << "This is the list of vertices on the destination boundary\n";
33727  // Get the pointer to the associated polyline by using the
33728  // boundary id
33729  TriangleMeshPolyLine *dst_polyline =
33730  this->boundary_polyline_pt(dst_bnd_id_final);
33731  // The number of vertices on the destination boundary
33732  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33733  // Loop over the vertices print them
33734  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33735  {
33736  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33737  error_message
33738  << "Vertex#("<<i<<"): ("
33739  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33740  }
33741  throw OomphLibError(
33742  error_message.str(),
33743  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33744  OOMPH_EXCEPTION_LOCATION);
33745 #endif
33746  } // else if (this->is_mesh_distributed())
33747 
33748  } // if (!found_vertex_on_dst_boundary_final)
33749  else
33750  {
33751  // Set the vertex number on the destination boundary
33752  polyline_pt->final_vertex_connected_n_vertex() =
33753  n_vertex_connection_final;
33754 
33755  // Set the chunk number on the destination boundary
33756  polyline_pt->final_vertex_connected_n_chunk() =
33757  sub_poly_to_connect;
33758 
33759  } // else if (!found_vertex_on_dst_boundary_final)
33760 
33761  } // if (polyline_pt->is_final_vertex_connected())
33762 
33763  }
33764 
33765  //=========================================================================
33766  /// \short Resume the boundary connections that may have been
33767  /// suspended because the destination boundary is no part of the
33768  /// domain. The connections are no permanently suspended because if
33769  /// load balance takes place the destination boundary may be part of
33770  /// the new domain representation therefore the connection would
33771  /// exist
33772  //=========================================================================
33773  template<class ELEMENT>
33775  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33776  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33777  {
33778  // Get the number of polylines that require to resume the connection
33779  // at the initial vertex
33780  const unsigned n_initial_poly =
33781  resume_initial_connection_polyline_pt.size();
33782  // Loop over the polylines that require to resume the connection
33783  // at the initial vertex
33784  for (unsigned p = 0; p < n_initial_poly; p++)
33785  {
33786  // Get the polyline
33787  TriangleMeshPolyLine* tmp_poly_pt =
33788  resume_initial_connection_polyline_pt[p];
33789  // Resume the connection with the initial vertex
33790  tmp_poly_pt->resume_initial_vertex_connected();
33791  } // for (p < n_initial_poly)
33792 
33793  // Get the number of polylines that require to resume the connection
33794  // at the final vertex
33795  const unsigned n_final_poly =
33796  resume_final_connection_polyline_pt.size();
33797  // Loop over the polylines that require to resume the connection at
33798  // the final vertex
33799  for (unsigned p = 0; p < n_final_poly; p++)
33800  {
33801  // Get the polyline
33802  TriangleMeshPolyLine* tmp_poly_pt =
33803  resume_final_connection_polyline_pt[p];
33804  // Resume the connection with the final vertex
33805  tmp_poly_pt->resume_final_vertex_connected();
33806  } // for (p < n_final_poly)
33807 
33808  // Clear the storage
33809  resume_initial_connection_polyline_pt.clear();
33810  resume_final_connection_polyline_pt.clear();
33811 
33812  }
33813 
33814 //=========================================================================
33815 /// \short Gets the associated vertex number according to the vertex
33816 /// coordinates on the destination boundary
33817 //=========================================================================
33818 template<class ELEMENT>
33821  Vector<double> &vertex_coordinates,
33822  const unsigned &dst_bnd_id,
33823  unsigned &vertex_number)
33824  {
33825 
33826  bool found_associated_vertex_number = false;
33827 
33828  // Get the pointer to the associated polyline by using the boundary id
33829  TriangleMeshPolyLine *dst_polyline =
33830  this->boundary_polyline_pt(dst_bnd_id);
33831 
33832  const unsigned n_vertices = dst_polyline->nvertex();
33833 
33834  // Loop over the vertices and return the closest vertex
33835  // to the given vertex coordinates
33836  for (unsigned i = 0; i < n_vertices; i++)
33837  {
33838 
33839  Vector<double> current_vertex =
33840  dst_polyline->vertex_coordinate(i);
33841 
33842  double error =
33843  (vertex_coordinates[0] - current_vertex[0])*
33844  (vertex_coordinates[0] - current_vertex[0])
33845  +
33846  (vertex_coordinates[1] - current_vertex[1])*
33847  (vertex_coordinates[1] - current_vertex[1]);
33848 
33849  error = sqrt(error);
33850 
33851  if(error <
33852  ToleranceForVertexMismatchInPolygons::Tolerable_error)
33853  {
33854  vertex_number = i;
33855  found_associated_vertex_number = true;
33856  break;
33857  }
33858 
33859  }
33860 
33861  return found_associated_vertex_number;
33862 
33863  }
33864 
33865 //=========================================================================
33866 /// \short Helper function that updates the input polygon's PSLG
33867 /// by using the end-points of elements from FaceMesh(es) that are
33868 /// constructed for the boundaries associated with the segments of the
33869 /// polygon. Optional boolean is used to run it as test only (if
33870 /// true is specified as input) in which case polygon isn't actually
33871 /// modified. Returned boolean indicates if polygon was (or would have
33872 /// been -- if called with check_only=false) changed.
33873 //=========================================================================
33874 template<class ELEMENT>
33876 update_polygon_using_face_mesh(TriangleMeshPolygon* polygon_pt,
33877  const bool& check_only)
33878  {
33879 #ifdef PARANOID
33880  // If the mesh is marked as distributed this method can not be
33881  // called since there is no guarantee of creating (distributed)
33882  // meshes that match in the number and position of nodes at their
33883  // shared boundaries. The only exececption is when called with
33884  // check_only=true, since no boundary updating is performed
33885  if (this->is_mesh_distributed() && !check_only)
33886  {
33887  std::stringstream error_message;
33888  error_message
33889  << "The updating of polygons of a distributed mesh can ONLY be\n"
33890  << "performed using the element's area associated to the halo(ed)\n"
33891  << "elements.\n"
33892  << "1) Make sure you have enabled the parallel mesh adaptation\n"
33893  << "option if you are working with a distributed mesh, OR\n"
33894  << "2) Make sure to call the update_..._using_elements_area() methods\n"
33895  << "if the mesh is marked as distributed\n\n";
33896  throw OomphLibError(error_message.str(),
33897  OOMPH_CURRENT_FUNCTION,
33898  OOMPH_EXCEPTION_LOCATION);
33899  } // if (this->is_mesh_distributed())
33900 #endif
33901 
33902  // Boolean that indicates whether an actual update of the polygon
33903  // was performed or not
33904  bool unrefinement_was_performed=false;
33905  bool refinement_was_performed=false;
33906  bool max_length_applied = false;
33907 
33908  //Loop over the number of polylines
33909  const unsigned n_polyline = polygon_pt->npolyline();
33910 
33911  // Get face mesh representation of all polylines, possibly
33912  // with segments re-distributed to maintain an approximately
33913  // even sub-division of the polygon
33914  Vector<Mesh*> face_mesh_pt;
33915  get_face_mesh_representation(polygon_pt,face_mesh_pt);
33916 
33917  // Create vertices for the polylines by using the vertices
33918  // of the FaceElements
33919  Vector<double> vertex_coord(3); // zeta,x,y
33920  Vector<double> bound_left(1);
33921  Vector<double> bound_right(1);
33922 
33923  for(unsigned p=0;p<n_polyline;p++)
33924  {
33925  // Set of coordinates that will be placed on the boundary
33926  // Set entries are ordered on first entry in vector which stores
33927  // the boundary coordinate so the vertices come out in order!
33928  std::set<Vector<double> > vertex_nodes;
33929 
33930  //Get the boundary id
33931  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
33932 
33933  // Get the chunk number
33934  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
33935 
33936  // Loop over the face elements (ordered) and add their vertices
33937  unsigned n_face_element = face_mesh_pt[p]->nelement();
33938  for(unsigned e=0;e<n_face_element;++e)
33939  {
33940  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
33941 
33942 #ifdef OOMPH_HAS_MPI
33943  // Only work with non-halo elements if the mesh is distributed
33944  if (this->is_mesh_distributed() && el_pt->is_halo()) {continue;}
33945 #endif
33946 
33947  unsigned n_node = el_pt->nnode();
33948 
33949  //Add the left-hand node to the set:
33950 
33951  // Boundary coordinate
33952  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
33953  vertex_coord[0] = bound_left[0];
33954 
33955  // Actual coordinates
33956  for(unsigned i=0;i<2;i++)
33957  {
33958  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
33959  }
33960  vertex_nodes.insert(vertex_coord);
33961 
33962  //Add the right-hand nodes to the set:
33963 
33964  //Boundary coordinate
33965  el_pt->node_pt(n_node-1)->
33966  get_coordinates_on_boundary(bound,bound_right);
33967  vertex_coord[0] = bound_right[0];
33968 
33969  // Actual coordinates
33970  for(unsigned i=0;i<2;i++)
33971  {
33972  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
33973  }
33974  vertex_nodes.insert(vertex_coord);
33975 
33976  }
33977 
33978  // Now turn into vector for ease of handling...
33979  unsigned n_poly_vertex = vertex_nodes.size();
33980  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
33981  unsigned count=0;
33982  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
33983  it!=vertex_nodes.end();++it)
33984  {
33985  tmp_vector_vertex_node[count].resize(3);
33986  tmp_vector_vertex_node[count][0] = (*it)[0];
33987  tmp_vector_vertex_node[count][1] = (*it)[1];
33988  tmp_vector_vertex_node[count][2] = (*it)[2];
33989  ++count;
33990  }
33991 
33992  // Size of the vector
33993  unsigned n_vertex=tmp_vector_vertex_node.size();
33994 
33995  // Tolerance below which the middle point can be deleted
33996  // (ratio of deflection to element length)
33997  double unrefinement_tolerance=
33998  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
33999 
34000  //------------------------------------------------------
34001  // Unrefinement
34002  //------------------------------------------------------
34003  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34004  {
34005  unrefinement_was_performed =
34006  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34007  unrefinement_tolerance, check_only);
34008 
34009  // In this case the "unrefinement_was_performed" variable
34010  // tell us if the update had been performed when calling
34011  // with check_oly=false
34012  if (check_only && unrefinement_was_performed)
34013  {
34014  // Cleanup (but only the elements -- the nodes still exist in
34015  // the bulk mesh!
34016  for(unsigned p=0;p<n_polyline;p++)
34017  {
34018  face_mesh_pt[p]->flush_node_storage();
34019  delete face_mesh_pt[p];
34020  }
34021  return true;
34022  }
34023 
34024  } // end of unrefinement
34025 
34026  // Do not perform refinement if there are no more than two vertices
34027  // New size of the vector
34028  n_vertex=tmp_vector_vertex_node.size();
34029 
34030  //------------------------------------------------
34031  // Refinement
34032  //------------------------------------------------
34033  double refinement_tolerance=
34034  polygon_pt->polyline_pt(p)->refinement_tolerance();
34035  if (refinement_tolerance>0.0 && n_vertex >= 2)
34036  {
34037  refinement_was_performed =
34038  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34039  refinement_tolerance, check_only);
34040 
34041  // In this case the "refinement_was_performed" variable
34042  // tell us if the update had been performed when calling
34043  // with check_only=false
34044  if (check_only && refinement_was_performed)
34045  {
34046  // Cleanup (but only the elements -- the nodes still exist in
34047  // the bulk mesh!
34048  for(unsigned p=0;p<n_polyline;p++)
34049  {
34050  face_mesh_pt[p]->flush_node_storage();
34051  delete face_mesh_pt[p];
34052  }
34053  return true;
34054  }
34055 
34056  } // end refinement
34057 
34058  // Do not perform maximum length constraint if there are no more than
34059  // two vertices
34060  // New size of the vector
34061  n_vertex=tmp_vector_vertex_node.size();
34062 
34063  //------------------------------------------------
34064  // Maximum length constrait
34065  //-----------------------------------------------
34066  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34067  if (maximum_length > 0.0 && n_vertex >= 2)
34068  {
34069  max_length_applied =
34070  apply_max_length_constraint(face_mesh_pt[p],
34071  tmp_vector_vertex_node,
34072  maximum_length);
34073 
34074  // In this case the max length criteria was applied, check if
34075  // check_only=false
34076  if (check_only && max_length_applied)
34077  {
34078  // Cleanup (but only the elements -- the nodes still exist in
34079  // the bulk mesh!
34080  for(unsigned p=0;p<n_polyline;p++)
34081  {
34082  face_mesh_pt[p]->flush_node_storage();
34083  delete face_mesh_pt[p];
34084  }
34085  return true;
34086  }
34087 
34088  }
34089 
34090  // For further processing the three-dimensional vector
34091  // has to be reduced to a two-dimensional vector
34092  n_vertex=tmp_vector_vertex_node.size();
34093  Vector<Vector<double> > vector_vertex_node(n_vertex);
34094 
34095  for(unsigned i=0;i<n_vertex;i++)
34096  {
34097  vector_vertex_node[i].resize(2);
34098  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34099  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34100  }
34101 
34102 #ifdef OOMPH_HAS_MPI
34103  // Only perform this checking if the mesh is not distributed. When
34104  // the mesh is distributed the polylines continuity is addressed in
34105  // the sort_polylines_helper() method
34106  if (!this->is_mesh_distributed())
34107 #endif
34108  {
34109  if ( (p > 0) && !check_only )
34110  {
34111  //Final end point of previous line
34112  Vector<double> final_vertex_of_previous_segment;
34113  unsigned n_prev_vertex =
34114  polygon_pt->curve_section_pt(p-1)->nvertex();
34115  final_vertex_of_previous_segment =
34116  polygon_pt->polyline_pt(p-1)->
34117  vertex_coordinate(n_prev_vertex-1);
34118 
34119  unsigned prev_seg_boundary_id =
34120  polygon_pt->curve_section_pt(p-1)->boundary_id();
34121 
34122  //Find the error between the final vertex of the previous
34123  //line and the first vertex of the current line
34124  double error = 0.0;
34125  for(unsigned i=0;i<2;i++)
34126  {
34127  const double dist =
34128  final_vertex_of_previous_segment[i] -
34129  (*vector_vertex_node.begin())[i];
34130  error += dist*dist;
34131  }
34132  error = sqrt(error);
34133 
34134  //If the error is bigger than the tolerance then
34135  //we probably need to reverse, but better check
34136  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34137  {
34138  //Find the error between the final vertex of the previous
34139  //line and the last vertex of the current line
34140  double rev_error = 0.0;
34141  for(unsigned i=0;i<2;i++)
34142  {
34143  const double dist =
34144  final_vertex_of_previous_segment[i] -
34145  (*--vector_vertex_node.end())[i];
34146  rev_error += dist*dist;
34147  }
34148  rev_error = sqrt(rev_error);
34149 
34150  if(rev_error >
34151  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34152  {
34153  // It could be possible that the first segment be reversed and we
34154  // did not notice it because this check does not apply for the
34155  // first segment. We can verify if the first segment is reversed
34156  // by using the vertex number 1
34157  if (p == 1)
34158  {
34159 
34160  //Initial end point of previous line
34161  Vector<double> initial_vertex_of_previous_segment;
34162 
34163  initial_vertex_of_previous_segment =
34164  polygon_pt->polyline_pt(p-1)->
34165  vertex_coordinate(0);
34166 
34167  unsigned prev_seg_boundary_id =
34168  polygon_pt->curve_section_pt(p-1)->boundary_id();
34169 
34170  //Find the error between the initial vertex of the previous
34171  //line and the first vertex of the current line
34172  double error = 0.0;
34173  for(unsigned i=0;i<2;i++)
34174  {
34175  const double dist =
34176  initial_vertex_of_previous_segment[i] -
34177  (*vector_vertex_node.begin())[i];
34178  error += dist*dist;
34179  }
34180  error = sqrt(error); // Reversed only the previous one
34181 
34182  //If the error is bigger than the tolerance then
34183  //we probably need to reverse, but better check
34184  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34185  {
34186  //Find the error between the final vertex of the previous
34187  //line and the last vertex of the current line
34188  double rev_error = 0.0;
34189  for(unsigned i=0;i<2;i++)
34190  {
34191  const double dist =
34192  initial_vertex_of_previous_segment[i] -
34193  (*--vector_vertex_node.end())[i];
34194  rev_error += dist*dist;
34195  }
34196  rev_error = sqrt(rev_error); // Reversed both the current one and
34197  // the previous one
34198 
34199  if (rev_error >
34200  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34201  {
34202  std::ostringstream error_stream;
34203  error_stream
34204  <<"The distance between the first node of the current\n"
34205  <<"line segment (boundary " << bound << ") and either end of "
34206  << "the previous line segment\n"
34207  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
34208  << "the desired tolerance " <<
34209  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34210  << "This suggests that the polylines defining the polygonal\n"
34211  << "representation are not properly ordered.\n"
34212  << "Fail on last vertex of polyline: ("
34213  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
34214  << bound << ").\nThis should have failed when first trying to "
34215  << "construct the\npolygon.\n";
34216  throw OomphLibError(error_stream.str(),
34217  OOMPH_CURRENT_FUNCTION,
34218  OOMPH_EXCEPTION_LOCATION);
34219 
34220  }
34221  else
34222  {
34223  // Reverse both
34224  // Reverse the current vector to line up with the previous one
34225  std::reverse(vector_vertex_node.begin(),
34226  vector_vertex_node.end());
34227 
34228  polygon_pt->polyline_pt(p-1)->reverse();
34229  }
34230  }
34231  else
34232  {
34233  // Reverse the previous one
34234  polygon_pt->polyline_pt(p-1)->reverse();
34235  }
34236 
34237  } // if p == 1
34238  else
34239  {
34240  std::ostringstream error_stream;
34241  error_stream
34242  <<"The distance between the first node of the current\n"
34243  <<"line segment (boundary " << bound << ") and either end of "
34244  << "the previous line segment\n"
34245  << "(boundary " << prev_seg_boundary_id << ") is bigger than the "
34246  << "desired tolerance " <<
34247  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34248  <<"This suggests that the polylines defining the polygonal\n"
34249  <<"representation are not properly ordered.\n"
34250  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
34251  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34252  << "This should have failed when first trying to construct the\n"
34253  << "polygon.\n";
34254  throw OomphLibError(error_stream.str(),
34255  OOMPH_CURRENT_FUNCTION,
34256  OOMPH_EXCEPTION_LOCATION);
34257  }
34258  }
34259  else
34260  {
34261  //Reverse the current vector to line up with the previous one
34262  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34263  }
34264 
34265  } // first error
34266  } // p > 0
34267  } // is mesh not distributed?
34268 
34269  if(!check_only)
34270  {
34271  // Now update the polyline according to the new vertices
34272  // The new one representation
34273  TriangleMeshPolyLine *tmp_polyline_pt =
34274  new TriangleMeshPolyLine(vector_vertex_node,bound);
34275 
34276  // Create a temporal "curve section" version of the recently created
34277  // polyline
34278  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
34279 
34280  // Establish refinement and unrefinement tolerance
34281  tmp_polyline_pt->set_unrefinement_tolerance(
34282  unrefinement_tolerance);
34283  tmp_polyline_pt->set_refinement_tolerance(
34284  refinement_tolerance);
34285 
34286  // Establish the maximum length constraint
34287  tmp_polyline_pt->set_maximum_length(maximum_length);
34288 
34289  // We pass the connection information from the old polyline to
34290  // the new one
34291  this->copy_connection_information(polygon_pt->polyline_pt(p),
34292  tmp_curve_section_pt);
34293 
34294  //Now update the polyline according to the new vertices but
34295  //first check if the object is allowed to delete the representation
34296  //or if it should be done by other object
34297  bool delete_it_on_destructor = false;
34298 
34299  std::set<TriangleMeshCurveSection*>::iterator it =
34300  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34301 
34302  if (it!=this->Free_curve_section_pt.end())
34303  {
34304  this->Free_curve_section_pt.erase(it);
34305  delete polygon_pt->curve_section_pt(p);
34306  delete_it_on_destructor = true;
34307  }
34308 
34309  // ------------------------------------------------------------
34310  // Copying the new representation
34311  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34312 
34313  // Update the Boundary - Polyline map
34314  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
34315 
34316  if (delete_it_on_destructor)
34317  {
34318  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34319  }
34320 
34321  } // if(!check_only)
34322 
34323  } // for (p < n_polyline)
34324 
34325  // Cleanup (but only the elements -- the nodes still exist in
34326  // the bulk mesh!
34327  for(unsigned p=0;p<n_polyline;p++)
34328  {
34329  face_mesh_pt[p]->flush_node_storage();
34330  delete face_mesh_pt[p];
34331  }
34332 
34333  if(check_only)
34334  {
34335  // if we end up all the way down here, no update of the internal boundaries
34336  // is necessary (in case we only check)
34337  return false;
34338  }
34339  else
34340  {
34341  // if we not only check, but actually perform the update and end up
34342  // all the way down here then we indicate whether an update was performed
34343  // or not
34344  return (unrefinement_was_performed ||
34345  refinement_was_performed ||
34346  max_length_applied);
34347  }
34348 
34349  }
34350 
34351 //=========================================================================
34352 /// \short Helper function that updates the input open curve by using
34353 /// end-points of elements from FaceMesh(es) that are constructed for the
34354 /// boundaries associated with the polylines. Optional boolean is used to
34355 /// run it as test only (if true is specified as input) in which case the
34356 /// polylines are not actually modified. Returned boolean indicates if
34357 /// polylines were (or would have been -- if called with check_only=false)
34358 /// changed.
34359 //=========================================================================
34360 template<class ELEMENT>
34362 update_open_curve_using_face_mesh(TriangleMeshOpenCurve* open_polyline_pt,
34363  const bool& check_only)
34364  {
34365 #ifdef PARANOID
34366  // If the mesh is marked as distributed this method can not be
34367  // called since there is no guarantee of creating (distributed)
34368  // meshes that match in the number and position of nodes at their
34369  // shared boundaries. The only exececption is when called with
34370  // check_only=true, since no boundary updating is performed
34371  if (this->is_mesh_distributed() && !check_only)
34372  {
34373  std::stringstream error_message;
34374  error_message
34375  << "The updating of open curves of a distributed mesh can ONLY be\n"
34376  << "performed using the element's area associated to the halo(ed)\n"
34377  << "elements.\n"
34378  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34379  << "option if you are working with a distributed mesh, OR\n"
34380  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34381  << "if the mesh is marked as distributed\n\n";
34382  throw OomphLibError(error_message.str(),
34383  OOMPH_CURRENT_FUNCTION,
34384  OOMPH_EXCEPTION_LOCATION);
34385  } // if (this->is_mesh_distributed())
34386 #endif
34387 
34388  // Boolean that indicates whether an actual update of the polylines
34389  // were performed or not
34390  bool unrefinement_was_performed=false;
34391  bool refinement_was_performed=false;
34392  bool max_length_applied = false;
34393 
34394  //Loop over the number of polylines
34395  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34396 
34397  // Get face mesh representation of all polylines, possibly
34398  // with segments re-distributed to maintain an approximately
34399  // even sub-division of the polygon
34400  Vector<Mesh*> face_mesh_pt;
34401  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34402 
34403  // Create vertices for the polylines by using the vertices
34404  // of the FaceElements
34405  Vector<double> vertex_coord(3); // zeta,x,y
34406  Vector<double> bound_left(1);
34407  Vector<double> bound_right(1);
34408 
34409  for(unsigned p=0;p<n_polyline;p++)
34410  {
34411  // Set of coordinates that will be placed on the boundary
34412  // Set entries are ordered on first entry in vector which stores
34413  // the boundary coordinate so the vertices come out in order!
34414  std::set<Vector<double> > vertex_nodes;
34415 
34416  //Get the boundary id
34417  const unsigned bound =
34418  open_polyline_pt->curve_section_pt(p)->boundary_id();
34419 
34420  // Get the chunk number
34421  const unsigned chunk =
34422  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34423 
34424  // Loop over the face elements (ordered) and add their vertices
34425  unsigned n_face_element = face_mesh_pt[p]->nelement();
34426 
34427  //n_count = 0;
34428  for(unsigned e=0;e<n_face_element;++e)
34429  {
34430  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34431  unsigned n_node = el_pt->nnode();
34432 
34433  //Add the left-hand node to the set:
34434 
34435  // Boundary coordinate
34436  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
34437  vertex_coord[0] = bound_left[0];
34438 
34439  // Actual coordinates
34440  for(unsigned i=0;i<2;i++)
34441  {
34442  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
34443  }
34444  vertex_nodes.insert(vertex_coord);
34445 
34446  //Add the right-hand nodes to the set:
34447 
34448  //Boundary coordinate
34449  el_pt->node_pt(n_node-1)->get_coordinates_on_boundary(bound,bound_right);
34450  vertex_coord[0] = bound_right[0];
34451 
34452  // Actual coordinates
34453  for(unsigned i=0;i<2;i++)
34454  {
34455  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
34456  }
34457  vertex_nodes.insert(vertex_coord);
34458 
34459  }
34460 
34461  // Now turn into vector for ease of handling...
34462  unsigned n_poly_vertex = vertex_nodes.size();
34463  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
34464  unsigned count=0;
34465  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
34466  it!=vertex_nodes.end();++it)
34467  {
34468  tmp_vector_vertex_node[count].resize(3);
34469  tmp_vector_vertex_node[count][0] = (*it)[0];
34470  tmp_vector_vertex_node[count][1] = (*it)[1];
34471  tmp_vector_vertex_node[count][2] = (*it)[2];
34472  ++count;
34473  }
34474 
34475  // Size of the vector
34476  unsigned n_vertex=tmp_vector_vertex_node.size();
34477 
34478  // Tolerance below which the middle point can be deleted
34479  // (ratio of deflection to element length)
34480  double unrefinement_tolerance=
34481  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34482 
34483  //------------------------------------------------------
34484  // Unrefinement
34485  //------------------------------------------------------
34486  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34487  {
34488  unrefinement_was_performed =
34489  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34490  unrefinement_tolerance, check_only);
34491 
34492  // In this case the unrefinement_was_performed variable actually
34493  // tell us if the update had been performed when calling
34494  // with check_only=false
34495  if (check_only && unrefinement_was_performed)
34496  {
34497  // Cleanup (but only the elements -- the nodes still exist in
34498  // the bulk mesh!
34499  for(unsigned p=0;p<n_polyline;p++)
34500  {
34501  face_mesh_pt[p]->flush_node_storage();
34502  delete face_mesh_pt[p];
34503  }
34504  return true;
34505  }
34506 
34507  } // end of unrefinement
34508 
34509  // Do not perform refinement if there are no more than two vertices
34510  // (open curve version)
34511  // New size of the vector
34512  n_vertex=tmp_vector_vertex_node.size();
34513 
34514  //------------------------------------------------
34515  /// Refinement
34516  //------------------------------------------------
34517  double refinement_tolerance=
34518  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34519  if (refinement_tolerance>0.0 && n_vertex >= 2)
34520  {
34521  refinement_was_performed =
34522  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34523  refinement_tolerance, check_only);
34524 
34525  // In this case the unrefinement_was_performed variable actually
34526  // tell us if the update had been performed when calling
34527  // with check_only=false
34528  if (check_only && refinement_was_performed)
34529  {
34530  // Cleanup (but only the elements -- the nodes still exist in
34531  // the bulk mesh!
34532  for(unsigned p=0;p<n_polyline;p++)
34533  {
34534  face_mesh_pt[p]->flush_node_storage();
34535  delete face_mesh_pt[p];
34536  }
34537  return true;
34538  }
34539 
34540  } // end refinement
34541 
34542  // Do not perform maximum length constraint if there are no more than
34543  // two vertices
34544  // New size of the vector
34545  n_vertex=tmp_vector_vertex_node.size();
34546 
34547  //------------------------------------------------
34548  // Maximum length constraint
34549  //-----------------------------------------------
34550  double maximum_length = open_polyline_pt->polyline_pt(p)->maximum_length();
34551  if (maximum_length > 0.0 && n_vertex >= 2)
34552  {
34553  bool max_length_applied = false;
34554  max_length_applied =
34555  apply_max_length_constraint(face_mesh_pt[p],
34556  tmp_vector_vertex_node,
34557  maximum_length);
34558 
34559  // In this case the max length criteria was applied, check if
34560  // check_only=false
34561  if (check_only && max_length_applied)
34562  {
34563  // Cleanup (but only the elements -- the nodes still exist in
34564  // the bulk mesh!
34565  for(unsigned p=0;p<n_polyline;p++)
34566  {
34567  face_mesh_pt[p]->flush_node_storage();
34568  delete face_mesh_pt[p];
34569  }
34570  return true;
34571  }
34572 
34573  }
34574 
34575  // For further processing the three-dimensional vector
34576  // has to be reduced to a two-dimensional vector
34577  n_vertex=tmp_vector_vertex_node.size();
34578  Vector<Vector<double> > vector_vertex_node(n_vertex);
34579 
34580  for(unsigned i=0;i<n_vertex;i++)
34581  {
34582  vector_vertex_node[i].resize(2);
34583  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34584  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34585  }
34586 
34587 #ifdef OOMPH_HAS_MPI
34588  // Only perform this checking if the mesh is not distributed. When
34589  // the mesh is distributed the polylines continuity is addressed
34590  // in the sort_polylines_helper() method
34591  if (!this->is_mesh_distributed())
34592 #endif
34593  {
34594  //Check whether the segments are continguous (first vertex of this
34595  //segment is equal to last vertex of previous segment).
34596  //If not, we should reverse the order of the current segment.
34597  //This check only applies for segments other than the first.
34598  //We only bother with this check, if we actually perform an update
34599  //of the polyline, i.e. if it's not only a check
34600  if( (p > 0) && !check_only )
34601  {
34602  //Final end point of previous line
34603  Vector<double> final_vertex_of_previous_segment;
34604  open_polyline_pt->polyline_pt(p-1)->
34605  final_vertex_coordinate(final_vertex_of_previous_segment);
34606 
34607  unsigned prev_seg_boundary_id =
34608  open_polyline_pt->curve_section_pt(p-1)->boundary_id();
34609 
34610  //Find the error between the final vertex of the previous
34611  //line and the first vertex of the current line
34612  double error = 0.0;
34613  for(unsigned i=0;i<2;i++)
34614  {
34615  const double dist =
34616  final_vertex_of_previous_segment[i] -
34617  (*vector_vertex_node.begin())[i];
34618  error += dist*dist;
34619  }
34620  error = sqrt(error);
34621 
34622  //If the error is bigger than the tolerance then
34623  //we probably need to reverse, but better check
34624  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34625  {
34626  //Find the error between the final vertex of the previous
34627  //line and the first vertex of the current line
34628  error = 0.0;
34629  for(unsigned i=0;i<2;i++)
34630  {
34631  const double dist =
34632  final_vertex_of_previous_segment[i] -
34633  (*--vector_vertex_node.end())[i];
34634  error += dist*dist;
34635  }
34636  error = sqrt(error);
34637 
34638  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34639  {
34640  // It could be possible that the first segment be reversed
34641  // and we did not notice it because this check does not
34642  // apply for the first segment. We can verify if the first
34643  // segment is reversed by using the vertex number 1
34644  if (p == 1)
34645  {
34646  // If no found it is possible that the previous polyline
34647  // be reversed Check for that case Initial point of
34648  // previous line
34649  Vector<double> initial_vertex_of_previous_segment;
34650  open_polyline_pt->polyline_pt(p-1)->
34651  initial_vertex_coordinate(initial_vertex_of_previous_segment);
34652 
34653  //Find the error between the initial vertex of the previous
34654  //line and the first vertex of the current line
34655  error = 0.0;
34656  for(unsigned i=0;i<2;i++)
34657  {
34658  const double dist =
34659  initial_vertex_of_previous_segment[i] -
34660  (*vector_vertex_node.begin())[i];
34661  error += dist*dist;
34662  }
34663  error = sqrt(error);
34664 
34665  //If the error is bigger than the tolerance then
34666  //we probably need to reverse, but better check
34667  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34668  {
34669  //Find the error between the final vertex of the previous
34670  //line and the first vertex of the current line
34671  error = 0.0;
34672  for(unsigned i=0;i<2;i++)
34673  {
34674  const double dist =
34675  initial_vertex_of_previous_segment[i] -
34676  (*--vector_vertex_node.end())[i];
34677  error += dist*dist;
34678  }
34679  error = sqrt(error);
34680 
34681  if(error >
34682  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34683  {
34684  std::ostringstream error_stream;
34685  error_stream
34686  <<"The distance between the first node of the current\n"
34687  <<"line segment (boundary " << bound
34688  <<") and either end of the previous line segment\n"
34689  <<"(boundary " << prev_seg_boundary_id << ") is bigger than "
34690  <<"the desired tolerance " <<
34691  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
34692  <<"This suggests that the polylines defining the open "
34693  << "curve\n"
34694  <<"representation are not properly ordered.\n"
34695  <<"Fail on last vertex of polyline: ("
34696  << prev_seg_boundary_id
34697  <<") and\nfirst vertex of polyline (" << bound << ").\n"
34698  <<"This should have failed when first trying to construct\n"
34699  <<"the open curve.\n";
34700  throw OomphLibError(error_stream.str(),
34701  OOMPH_CURRENT_FUNCTION,
34702  OOMPH_EXCEPTION_LOCATION);
34703  }
34704  else // We have to reverse both
34705  {
34706  // First reverse the previous polyline
34707  open_polyline_pt->polyline_pt(p-1)->reverse();
34708  // Then reverse the current polyline
34709  std::reverse(vector_vertex_node.begin(),
34710  vector_vertex_node.end());
34711  }
34712  }
34713  else
34714  {
34715  // Reverse the previous polyline only
34716  open_polyline_pt->polyline_pt(p-1)->reverse();
34717  }
34718  } // if (p == 1)
34719  else
34720  {
34721  std::ostringstream error_stream;
34722  error_stream
34723  << "The distance between the first node of the current\n"
34724  << "line segment (boundary " << bound << ") and either end of "
34725  << "the previous line segment\n"
34726  << "(boundary "<<prev_seg_boundary_id<<") is bigger than the "
34727  << "desired tolerance " <<
34728  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34729  <<"This suggests that the polylines defining the polygonal\n"
34730  <<"representation are not properly ordered.\n"
34731  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
34732  << ") and\nfirst vertex of polyline ("<<bound<<").\n"
34733  << "This should have failed when first trying to construct the\n"
34734  << "polygon.\n";
34735  throw OomphLibError(error_stream.str(),
34736  OOMPH_CURRENT_FUNCTION,
34737  OOMPH_EXCEPTION_LOCATION);
34738  }
34739  }
34740  else
34741  {
34742  //Reverse the current vector to line up with the previous one
34743  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34744  }
34745 
34746  }
34747 
34748  } // if p > 0
34749 
34750  } // is mesh not distributed?
34751 
34752  if(!check_only)
34753  {
34754  // Now update the polyline according to the new vertices The new
34755  // one representation
34756  TriangleMeshPolyLine *tmp_polyline =
34757  new TriangleMeshPolyLine(vector_vertex_node, bound);
34758 
34759  // Create a temporal "curve section" version of the recently
34760  // created polyline
34761  TriangleMeshCurveSection *tmp_curve_section = tmp_polyline;
34762 
34763  // Copy the unrefinement and refinement information
34764  tmp_polyline->set_unrefinement_tolerance(
34765  unrefinement_tolerance);
34766  tmp_polyline->set_refinement_tolerance(
34767  refinement_tolerance);
34768 
34769  // Establish the maximum length constraint
34770  tmp_polyline->set_maximum_length(maximum_length);
34771 
34772  // Pass the connection information from the old polyline to the
34773  // new one
34774  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
34775  tmp_curve_section);
34776 
34777  std::set<TriangleMeshCurveSection*>::iterator it =
34778  this->Free_curve_section_pt.find(open_polyline_pt->curve_section_pt(p));
34779 
34780  bool delete_it_on_destructor = false;
34781 
34782  if (it!=this->Free_curve_section_pt.end())
34783  {
34784  // Free previous representation only if you created
34785  this->Free_curve_section_pt.erase(it);
34786  delete open_polyline_pt->curve_section_pt(p);
34787  delete_it_on_destructor = true;
34788  }
34789 
34790  // *****************************************************************
34791  // Copying the new representation
34792  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
34793 
34794  // Update the Boundary <--> PolyLine map
34795  this->Boundary_curve_section_pt[bound] =
34796  open_polyline_pt->curve_section_pt(p);
34797 
34798  if (delete_it_on_destructor)
34799  {
34800  this->Free_curve_section_pt.insert(
34801  open_polyline_pt->curve_section_pt(p));
34802  }
34803 
34804  } // if(!check_only)
34805 
34806  } // n_polylines
34807 
34808  // Cleanup (but only the elements -- the nodes still exist in
34809  // the bulk mesh!
34810  for(unsigned p=0;p<n_polyline;p++)
34811  {
34812  face_mesh_pt[p]->flush_node_storage();
34813  delete face_mesh_pt[p];
34814  }
34815 
34816  if(check_only)
34817  {
34818  // if we end up all the way down here, no update of the internal
34819  // boundaries is necessary (in case we only check)
34820  return false;
34821  }
34822  else
34823  {
34824  // if we not only check, but actually perform the update and end
34825  // up all the way down here then we indicate whether an update was
34826  // performed or not
34827  return (unrefinement_was_performed ||
34828  refinement_was_performed ||
34829  max_length_applied);
34830  }
34831 
34832  }
34833 
34834 //=========================================================================
34835 /// \short Helper function that performs the unrefinement process
34836 /// on the specified boundary by using the provided vertices
34837 /// representation. Optional boolean is used to run it as test only (if
34838 /// true is specified as input) in which case vertex coordinates aren't
34839 /// actually modified. Returned boolean indicates if polyline was (or
34840 /// would have been -- if called with check_only=false) changed.
34841 //=========================================================================
34842 template<class ELEMENT>
34844 unrefine_boundary(const unsigned &b,
34845  const unsigned &c,
34846  Vector<Vector<double> > &vector_bnd_vertices,
34847  double &unrefinement_tolerance,
34848  const bool &check_only)
34849  {
34850  // Store the vertices not allowed for deletion
34851  std::set<Vector<double> > no_delete_vertex;
34852 
34853  // Does the boundary receives connections?
34854  const bool boundary_receive_connections =
34855  this->boundary_connections(b, c, no_delete_vertex);
34856 
34857  // Boolean that indicates whether an actual update of the vertex
34858  // coordinates was performed or not
34859  bool unrefinement_was_performed=false;
34860 
34861  unsigned n_vertex = vector_bnd_vertices.size();
34862 
34863  // Initialise counter that indicates at which vertex we're currently
34864  // considering for deletion
34865  unsigned counter=1;
34866 
34867  // Loop over the nodes; start with the second one and increment by two
34868  // this way a "pack" of three nodes will be considered for calculation:
34869  // the middle-node (which is to be deleted or not) and the adjacent
34870  // nodes
34871  for(unsigned i=1;i<=n_vertex-2;i+=2)
34872  {
34873  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34874  double a_x=vector_bnd_vertices[i-1][1];
34875  double a_y=vector_bnd_vertices[i-1][2];
34876  double b_x=vector_bnd_vertices[i][1];
34877  double b_y=vector_bnd_vertices[i][2];
34878  double c_x=vector_bnd_vertices[i+1][1];
34879  double c_y=vector_bnd_vertices[i+1][2];
34880 
34881  double a=b_x-a_x;
34882  double b=b_y-a_y;
34883  double c=c_x-a_x;
34884  double d=c_y-a_y;
34885 
34886  double e=a*(a_x+b_x)+b*(a_y+b_y);
34887  double f=c*(a_x+c_x)+d*(a_y+c_y);
34888 
34889  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
34890 
34891  bool do_it=false;
34892  if (std::fabs(g)<1.0e-14)
34893  {
34894  do_it=true;
34895  if(check_only) {return true;}
34896  }
34897  else
34898  {
34899  double p_x=(d*e-b*f)/g;
34900  double p_y=(a*f-c*e)/g;
34901 
34902  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
34903 
34904  double rhalfca_x=0.5*(a_x-c_x);
34905  double rhalfca_y=0.5*(a_y-c_y);
34906 
34907  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
34908 
34909  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
34910 
34911  // If sticky out bit divided by distance between end nodes
34912  // is less than tolerance the boundary is so flat that we
34913  // can safely kill the node
34914  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
34915  unrefinement_tolerance)
34916  {
34917  do_it=true;
34918  if(check_only) {return true;}
34919  }
34920  }
34921 
34922  // If the vertex was proposed for deletion check that it is
34923  // allowed for being deleted
34924  if (do_it && boundary_receive_connections)
34925  {
34926  // Is the vertex one of the non deletable vertices
34927  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
34928  it != no_delete_vertex.end(); it++)
34929  {
34930  // Compute the distance between the proposed node to delete
34931  // and the ones that should not be deleted
34932  const double x = (*it)[0];
34933  const double y = (*it)[1];
34934  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
34935  error = sqrt(error);
34936 
34937  if(error<ToleranceForVertexMismatchInPolygons::Tolerable_error)
34938  {
34939  // Do not delete the vertex
34940  do_it = false;
34941  break;
34942  }
34943 
34944  }
34945 
34946  } // if (do_it && boundary_receive_connections)
34947 
34948  // Remove node?
34949  if (do_it)
34950  {
34951  vector_bnd_vertices[i].resize(0);
34952  }
34953 
34954  // Increase the counter, that indicates the number of the
34955  // next middle node
34956  counter+=2;
34957  }
34958 
34959  // coming out of here the value of counter is the index of the
34960  // last node on the polyline counter=n_vertex-1 (in case of an
34961  // even number of nodes) or counter has the value of the number
34962  // of nodes on the polyline counter=n_vertex (in case of an odd
34963  // number of nodes
34964 
34965  // Special treatment for the end of the polyline:
34966  // If the number of nodes is even, then the previous loop stopped
34967  // at the last but second node, i.e. the current value of counter
34968  // is the index of the last node. If that's the case, the last but
34969  // one node needs to be treated separately
34970  if( (counter)==(n_vertex-1) )
34971  {
34972  // Set the last but one node as middle node
34973  unsigned i=vector_bnd_vertices.size()-2;
34974 
34975  // Index of the current! last but second node (considering any
34976  // previous deletion)
34977  unsigned n=0;
34978 
34979  if(vector_bnd_vertices[counter-2].size()!=0)
34980  {
34981  // if the initial last but second node does still exist then
34982  // this one is obviously also the current last but second one
34983  n=counter-2;
34984  }
34985  else
34986  {
34987  // if the initial last but second node was deleted then the
34988  // initial last but third node is the current last but second
34989  // node
34990  n=counter-3;
34991  }
34992 
34993  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
34994  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
34995  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
34996 
34997  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34998  double a_x=vector_bnd_vertices[n][1];
34999  double a_y=vector_bnd_vertices[n][2];
35000  double b_x=vector_bnd_vertices[i][1];
35001  double b_y=vector_bnd_vertices[i][2];
35002  double c_x=vector_bnd_vertices[i+1][1];
35003  double c_y=vector_bnd_vertices[i+1][2];
35004 
35005  double a=b_x-a_x;
35006  double b=b_y-a_y;
35007  double c=c_x-a_x;
35008  double d=c_y-a_y;
35009 
35010  double e=a*(a_x+b_x)+b*(a_y+b_y);
35011  double f=c*(a_x+c_x)+d*(a_y+c_y);
35012 
35013  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
35014 
35015  bool do_it=false;
35016  if (std::fabs(g)<1.0e-14)
35017  {
35018  do_it=true;
35019  if(check_only) {return true;}
35020  }
35021  else
35022  {
35023  double p_x=(d*e-b*f)/g;
35024  double p_y=(a*f-c*e)/g;
35025 
35026  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
35027 
35028  double rhalfca_x=0.5*(a_x-c_x);
35029  double rhalfca_y=0.5*(a_y-c_y);
35030 
35031  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
35032 
35033  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
35034 
35035  // If sticky out bit divided by distance between end nodes
35036  // is less than tolerance the boundary is so flat that we
35037  // can safely kill the node
35038  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
35039  unrefinement_tolerance)
35040  {
35041  do_it=true;
35042  if(check_only) {return true;}
35043  }
35044  }
35045 
35046  // If the vertex was proposed for deletion check that it is
35047  // allowed for being deleted
35048  if (do_it && boundary_receive_connections)
35049  {
35050  // Is the vertex one of the non deletable vertices
35051  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
35052  it != no_delete_vertex.end(); it++)
35053  {
35054  // Compute the distance between the proposed node to delete
35055  // and the ones that should not be deleted
35056  const double x = (*it)[0];
35057  const double y = (*it)[1];
35058  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
35059  error = sqrt(error);
35060 
35061  if(error <
35062  ToleranceForVertexMismatchInPolygons::Tolerable_error)
35063  {
35064  // Do not delete the vertex
35065  do_it = false;
35066  break;
35067  }
35068 
35069  }
35070 
35071  } // if (do_it && boundary_receive_connections)
35072 
35073  // Remove node?
35074  if (do_it)
35075  {
35076  vector_bnd_vertices[i].resize(0);
35077  }
35078  }
35079 
35080  // Create another vector, which will only contain entries of
35081  // nodes that still exist
35082  Vector<Vector<double> > compact_vector;
35083  compact_vector.reserve(n_vertex);
35084  for (unsigned i=0;i<n_vertex;i++)
35085  {
35086  // If the entry was not deleted include it in the new vector
35087  if (vector_bnd_vertices[i].size()!=0)
35088  {
35089  compact_vector.push_back(vector_bnd_vertices[i]);
35090  }
35091  }
35092 
35093  /// Get the size of the vector that now includes all remaining nodes
35094  n_vertex =compact_vector.size();
35095 
35096  // If the size of the vector containing the remaining nodes is
35097  // different from the size of the vector before the unrefinement
35098  // routine (with the original nodes)
35099  // then the polyline was obviously updated
35100  if( n_vertex != vector_bnd_vertices.size() )
35101  {
35102  unrefinement_was_performed=true;
35103  }
35104 
35105  /// Copy back
35106  vector_bnd_vertices.resize(n_vertex);
35107  for(unsigned i=0;i<n_vertex;i++)
35108  {
35109  vector_bnd_vertices[i].resize(3);
35110  vector_bnd_vertices[i][0]=compact_vector[i][0];
35111  vector_bnd_vertices[i][1]=compact_vector[i][1];
35112  vector_bnd_vertices[i][2]=compact_vector[i][2];
35113  }
35114 
35115  return unrefinement_was_performed;
35116 
35117  }
35118 
35119 //=========================================================================
35120 /// \short Helper function that performs the refinement process
35121 /// on the specified boundary by using the provided vertices
35122 /// representation. Optional boolean is used to run it as test only (if
35123 /// true is specified as input) in which case vertex coordinates aren't
35124 /// actually modified. Returned boolean indicates if polyline was (or
35125 /// would have been -- if called with check_only=false) changed.
35126 //=========================================================================
35127 template<class ELEMENT>
35129 refine_boundary(Mesh* face_mesh_pt,
35130  Vector<Vector<double> > &vector_bnd_vertices,
35131  double &refinement_tolerance,
35132  const bool &check_only)
35133  {
35134  // Boolean that indicates whether an actual update of the vertex
35135  // coordinates was performed or not
35136  bool refinement_was_performed=false;
35137 
35138  // Create a geometric object from the mesh to represent
35139  //the curvilinear boundary
35140  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35141 
35142  // Get the total number of current vertices
35143  unsigned n_vertex=vector_bnd_vertices.size();
35144 
35145  // Create a new (temporary) vector for the nodes, so
35146  // that new nodes can be stored
35147  Vector<Vector<double> > extended_vector;
35148 
35149  // Reserve memory space for twice the number of already
35150  // existing nodes (worst case)
35151  extended_vector.reserve(2*n_vertex);
35152 
35153  // Loop over the nodes until the last but one node
35154  for(unsigned inod=0;inod<n_vertex-1;inod++)
35155  {
35156  // Get local coordinate of "left" node
35157  double zeta_left=vector_bnd_vertices[inod][0];
35158 
35159  // Get position vector of "left" node
35160  Vector<double> R_left(2);
35161  for(unsigned i=0;i<2;i++)
35162  {
35163  R_left[i]=vector_bnd_vertices[inod][i+1];
35164  }
35165 
35166  // Get local coordinate of "right" node
35167  double zeta_right=vector_bnd_vertices[inod+1][0];
35168 
35169  // Get position vector of "right" node
35170  Vector<double> R_right(2);
35171  for(unsigned i=0;i<2;i++)
35172  {
35173  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35174  }
35175 
35176  // Get the boundary coordinate of the midpoint
35177  Vector<double> zeta_mid(1);
35178  zeta_mid[0]=0.5*(zeta_left+zeta_right);
35179 
35180  // Get the position vector of the midpoint on the
35181  // curvilinear boundary
35182  Vector<double> R_mid(2);
35183  mesh_geom_obj_pt->position(zeta_mid,R_mid);
35184 
35185  // Get the position vector of the midpoint on the straight
35186  // line connecting "left" and "right" node
35187  Vector<double> R_mid_polygon(2);
35188  for(unsigned i=0;i<2;i++)
35189  {
35190  R_mid_polygon[i]=0.5*(R_right[i]+R_left[i]);
35191  }
35192 
35193  // Calculate the distance between the midpoint on the curvilinear
35194  // boundary and the midpoint on the straight line
35195  double distance=sqrt((R_mid[0]-R_mid_polygon[0])*
35196  (R_mid[0]-R_mid_polygon[0])+
35197  (R_mid[1]-R_mid_polygon[1])*
35198  (R_mid[1]-R_mid_polygon[1]));
35199 
35200  // Calculating the length of the straight line
35201  double length=sqrt((R_right[0]-R_left[0])*(R_right[0]-R_left[0])+
35202  (R_right[1]-R_left[1])*(R_right[1]-R_left[1]));
35203 
35204  // If the ratio of distance between the midpoints to the length
35205  // of the straight line is larger than the tolerance
35206  // specified for the criterion when points can be deleted,
35207  // create a new node and add it to the (temporary) vector
35208  if((distance/length) > refinement_tolerance)
35209  {
35210 
35211  if(check_only)
35212  {
35213  // Delete the allocated memory for the geometric object
35214  // that represents the curvilinear boundary
35215  delete mesh_geom_obj_pt;
35216  return true;
35217  }
35218 
35219  Vector<double> new_node(3);
35220  new_node[0]=zeta_mid[0];
35221  new_node[1]=R_mid[0];
35222  new_node[2]=R_mid[1];
35223 
35224  // Include the "left" node in the new "temporary" vector
35225  extended_vector.push_back(vector_bnd_vertices[inod]);
35226 
35227  // Include the new node as well
35228  extended_vector.push_back(new_node);
35229 
35230  }
35231  else
35232  {
35233  // Include the "left" node in the new "temporary" vector
35234  // and move on to the next node
35235  extended_vector.push_back(vector_bnd_vertices[inod]);
35236  }
35237  } // end of loop over nodes
35238 
35239  // Add the last node to the vector
35240  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35241 
35242  /// Get the size of the vector that now includes all added nodes
35243  n_vertex=extended_vector.size();
35244 
35245  // If the size of the vector including the added nodes is
35246  // different from the size of the vector before the refinement
35247  // routine then the polyline was obviously updated
35248  if( n_vertex != vector_bnd_vertices.size() )
35249  {
35250  refinement_was_performed=true;
35251  }
35252 
35253  // Copy across
35254  vector_bnd_vertices.resize(n_vertex);
35255  for(unsigned i=0;i<n_vertex;i++)
35256  {
35257  vector_bnd_vertices[i].resize(3);
35258  vector_bnd_vertices[i][0]=extended_vector[i][0];
35259  vector_bnd_vertices[i][1]=extended_vector[i][1];
35260  vector_bnd_vertices[i][2]=extended_vector[i][2];
35261  }
35262 
35263  // Delete the allocated memory for the geometric object
35264  // that represents the curvilinear boundary
35265  delete mesh_geom_obj_pt;
35266 
35267  return refinement_was_performed;
35268 
35269  }
35270 
35271  //=========================================================================
35272  // \short Helper function that applies the maximum length constraint
35273  // when it was specified. This will increase the number of points in
35274  // the current curve section in case that any segment on it does not
35275  // fulfils the requirement
35276  //=========================================================================
35277  template<class ELEMENT>
35279  apply_max_length_constraint(Mesh* face_mesh_pt,
35280  Vector<Vector<double> > &vector_bnd_vertices,
35281  double &max_length_constraint)
35282  {
35283  // Boolean that indicates whether an actual update of the vertex
35284  // coordinates was performed or not
35285  bool max_length_applied=false;
35286 
35287  // Create a geometric object from the mesh to represent
35288  //the curvilinear boundary
35289  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35290 
35291  // Get the total number of current vertices
35292  unsigned n_vertex=vector_bnd_vertices.size();
35293 
35294  // Create a new (temporary) vector for the nodes, so
35295  // that new nodes can be stored
35296  Vector<Vector<double> > extended_vector;
35297 
35298  // Loop over the nodes until the last but one node
35299  for(unsigned inod=0;inod<n_vertex-1;inod++)
35300  {
35301  // Get local coordinate of "left" node
35302  double zeta_left=vector_bnd_vertices[inod][0];
35303 
35304  // Get position vector of "left" node
35305  Vector<double> R_left(2);
35306  for(unsigned i=0;i<2;i++)
35307  {
35308  R_left[i]=vector_bnd_vertices[inod][i+1];
35309  }
35310 
35311  // Get local coordinate of "right" node
35312  double zeta_right=vector_bnd_vertices[inod+1][0];
35313 
35314  // Get position vector of "right" node
35315  Vector<double> R_right(2);
35316  for(unsigned i=0;i<2;i++)
35317  {
35318  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35319  }
35320 
35321  // Include the "left" node in the new "temporary" vector
35322  extended_vector.push_back(vector_bnd_vertices[inod]);
35323 
35324  // Check whether the current distance between the left and right node
35325  // is longer than the specified constraint or not
35326  double length=std::fabs(zeta_right-zeta_left);
35327 
35328  // Do we need to introduce new nodes?
35329  if (length > max_length_constraint)
35330  {
35331  double n_pts = length/max_length_constraint;
35332  // We only want the integer part
35333  unsigned n_points = static_cast<unsigned>(n_pts);
35334  double zeta_increment = (zeta_right-zeta_left)/((double)n_points+1);
35335 
35336  Vector<double> zeta(1);
35337  // Create the n_points+1 points inside the segment
35338  for(unsigned s=1;s<n_points+1;s++)
35339  {
35340  // Get the coordinates
35341  zeta[0]= zeta_left + zeta_increment*double(s);
35342  Vector<double> vertex(2);
35343  mesh_geom_obj_pt->position(zeta, vertex);
35344 
35345  // Create the new node
35346  Vector<double> new_node(3);
35347  new_node[0]=zeta[0];
35348  new_node[1]=vertex[0];
35349  new_node[2]=vertex[1];
35350 
35351  // Include the new node
35352  extended_vector.push_back(new_node);
35353  }
35354  }
35355  }
35356 
35357  // Add the last node to the vector
35358  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35359 
35360  /// Get the size of the vector that now includes all added nodes
35361  n_vertex=extended_vector.size();
35362 
35363  // If the size of the vector including the added nodes is
35364  // different from the size of the vector before applying the maximum length
35365  // constraint then the polyline was obviously updated
35366  if( n_vertex != vector_bnd_vertices.size() )
35367  {
35368  max_length_applied = true;
35369  }
35370 
35371  // Copy across
35372  vector_bnd_vertices.resize(n_vertex);
35373  for(unsigned i=0;i<n_vertex;i++)
35374  {
35375  vector_bnd_vertices[i].resize(3);
35376  vector_bnd_vertices[i][0]=extended_vector[i][0];
35377  vector_bnd_vertices[i][1]=extended_vector[i][1];
35378  vector_bnd_vertices[i][2]=extended_vector[i][2];
35379  }
35380 
35381  // Delete the allocated memory for the geometric object
35382  // that represents the curvilinear boundary
35383  delete mesh_geom_obj_pt;
35384 
35385  return max_length_applied;
35386 
35387  }
35388 
35389 //=========================================================================
35390 /// \short Helper function
35391 /// Creates an unsorted face mesh representation from the specified
35392 /// boundary id. It means that the elements are not sorted along the
35393 /// boundary
35394 //=========================================================================
35395 template<class ELEMENT>
35398  const unsigned &boundary_id,
35399  Mesh* face_mesh_pt)
35400  {
35401  // Create a face mesh adjacent to specified boundary.
35402  // The face mesh consists of FaceElements that may also be
35403  // interpreted as GeomObjects
35404 
35405  // Build the face mesh
35406  this->template build_face_mesh<ELEMENT,FaceElementAsGeomObject>
35407  (boundary_id,face_mesh_pt);
35408 
35409  // Find the total number of added elements
35410  unsigned n_element = face_mesh_pt->nelement();
35411  // Loop over the elements
35412  for(unsigned e=0;e<n_element;e++)
35413  {
35414 
35415  //Cast the element pointer to the correct thing!
35416  FaceElementAsGeomObject<ELEMENT>* el_pt=
35417  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
35418  (face_mesh_pt->element_pt(e));
35419 
35420  // Set bulk boundary number
35421  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35422 
35423  }
35424 
35425  }
35426 
35427 //=========================================================================
35428 /// \short Helper function
35429 /// Creates a sorted face mesh representation of the specified PolyLine
35430 /// It means that the elements are sorted along the boundary
35431 //=========================================================================
35432 template<class ELEMENT>
35435  const unsigned &boundary_id,
35436  Mesh* face_mesh_pt,
35437  std::map<FiniteElement*, bool> &is_inverted,
35438  bool &inverted_face_mesh)
35439  {
35440  Mesh *tmp_unsorted_face_mesh_pt = new Mesh();
35441 
35442  // First step we get the unsorted version of the face mesh
35443  create_unsorted_face_mesh_representation(
35444  boundary_id, tmp_unsorted_face_mesh_pt);
35445 
35446  // Once with the unsorted version of the face mesh
35447  // only left to sort it out!!!
35448 
35449  // Put all face elements in order
35450  //-------------------------------
35451 
35452  // Put first element into ordered list
35453  // Temporal list for sorting the elements
35454  std::list<FiniteElement*> sorted_el_pt;
35455  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35456  sorted_el_pt.push_back(el_pt);
35457 
35458  // Number of nodes
35459  unsigned nnod=el_pt->nnode();
35460 
35461  // Count elements that have been done
35462  unsigned count_done=0;
35463 
35464  // How many face elements are there?
35465  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35466 
35467  // Keep track of who's done
35468  std::map<FiniteElement*,bool> done_el;
35469 
35470  is_inverted.clear();
35471 
35472  // Fit in the other elements in at most nel^2 loops
35473  for (unsigned ee=1;ee<n_face_element;ee++)
35474  {
35475  // Loop over all elements to check if they fit to the right
35476  // or the left of the current one
35477  for (unsigned e=1;e<n_face_element;e++)
35478  {
35479  // Candidate element
35480  el_pt=tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35481 
35482  // Is it done yet?
35483  if (!done_el[el_pt])
35484  {
35485  // Left and rightmost elements
35486  FiniteElement* first_el_pt=(*sorted_el_pt.begin());
35487  std::list<FiniteElement*>::iterator it=sorted_el_pt.end();
35488  it--;
35489  FiniteElement* last_el_pt=*it;
35490 
35491  // Left and rightmost nodes
35492  Node* left_node_pt=first_el_pt->node_pt(0);
35493  if (is_inverted[first_el_pt])
35494  {
35495  left_node_pt=first_el_pt->node_pt(nnod-1);
35496  }
35497  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35498  if (is_inverted[last_el_pt])
35499  {
35500  right_node_pt=last_el_pt->node_pt(0);
35501  }
35502 
35503  // New element fits at the left of first element and is not inverted
35504  if (left_node_pt==el_pt->node_pt(nnod-1))
35505  {
35506  sorted_el_pt.push_front(el_pt);
35507  done_el[el_pt]=true;
35508  count_done++;
35509  is_inverted[el_pt]=false;
35510  }
35511  // New element fits at the left of first element and is inverted
35512 
35513  else if (left_node_pt==el_pt->node_pt(0))
35514  {
35515  sorted_el_pt.push_front(el_pt);
35516  done_el[el_pt]=true;
35517  count_done++;
35518  is_inverted[el_pt]=true;
35519  }
35520  // New element fits on the right of last element and is not inverted
35521 
35522  else if(right_node_pt==el_pt->node_pt(0))
35523  {
35524  sorted_el_pt.push_back(el_pt);
35525  done_el[el_pt]=true;
35526  count_done++;
35527  is_inverted[el_pt]=false;
35528  }
35529  // New element fits on the right of last element and is inverted
35530 
35531  else if (right_node_pt==el_pt->node_pt(nnod-1))
35532  {
35533  sorted_el_pt.push_back(el_pt);
35534  done_el[el_pt]=true;
35535  count_done++;
35536  is_inverted[el_pt]=true;
35537  }
35538 
35539  if (done_el[el_pt])
35540  {
35541  break;
35542  }
35543  }
35544  }
35545  }
35546 
35547  // Are we done?
35548  if (count_done!=(n_face_element-1))
35549  {
35550  std::ostringstream error_message;
35551  error_message
35552  << "When ordering FaceElements on "
35553  << "boundary " << boundary_id << " only managed to order \n" << count_done
35554  << " of " << n_face_element << " face elements.\n"
35555  << std::endl;
35556  throw OomphLibError(
35557  error_message.str(),
35558  OOMPH_CURRENT_FUNCTION,
35559  OOMPH_EXCEPTION_LOCATION);
35560  }
35561 
35562  // Now make a mesh that contains the FaceElements in order
35563  // Remember that we currently have a list, not a mesh of sorted elements
35564 
35565  // Fill it
35566  for (std::list<FiniteElement*>::iterator it=sorted_el_pt.begin();
35567  it!=sorted_el_pt.end();it++)
35568  {
35569  // Get element
35570  FiniteElement* el_pt=*it;
35571 
35572  // add this face element to the order original mesh
35573  face_mesh_pt->add_element_pt(el_pt);
35574  }
35575 
35576  // Verify if face mesh representation is not inverted according to the
35577  // polyline specified by the user, it means that the initial and the
35578  // final vertex does really correspond to the first and last vertex
35579  // respectively, if not, state that the face mesh representation is
35580  // inverted
35581 
35582  // Get the associated polyline representation to the boundary
35583  TriangleMeshPolyLine *bnd_polyline =
35584  this->Boundary_curve_section_pt[boundary_id];
35585 
35586  // Get the really first vertex
35587  Vector<double> first_vertex =
35588  bnd_polyline->vertex_coordinate(0);
35589 
35590  // Now get the first node based on the face mesh representation
35591  // First get access to the first element
35592  FiniteElement* first_el_pt =
35593  face_mesh_pt->finite_element_pt(0);
35594 
35595  // Now get access to the first node
35596  unsigned n_node = first_el_pt->nnode();
35597  // Get the very first node (taking into account if it is
35598  // inverted or not!!)
35599  Node* first_node_pt = first_el_pt->node_pt(0);
35600  if (is_inverted[first_el_pt])
35601  {
35602  first_node_pt = first_el_pt->node_pt(n_node-1);
35603  }
35604 
35605  double error = (first_node_pt->x(0) - first_vertex[0])*
35606  (first_node_pt->x(0) - first_vertex[0]) +
35607  (first_node_pt->x(1) - first_vertex[1])*
35608  (first_node_pt->x(1) - first_vertex[1]);
35609 
35610  error = sqrt(error);
35611 
35612  if(error <
35613  ToleranceForVertexMismatchInPolygons::Tolerable_error)
35614  {
35615  inverted_face_mesh = false;
35616  }
35617  else
35618  {
35619  inverted_face_mesh = true;
35620  }
35621 
35622  }
35623 
35624 //=========================================================================
35625 /// Helper function to construct face mesh representation of all polylines,
35626 /// possibly with segments re-distributed between polylines
35627 /// to maintain an approximately even sub-division of the polygon
35628 //=========================================================================
35629 template<class ELEMENT>
35631 get_face_mesh_representation(TriangleMeshPolygon* polygon_pt,
35632  Vector<Mesh*>& face_mesh_pt)
35633  {
35634  // Number of polylines
35635  unsigned n_polyline = polygon_pt->npolyline();
35636  face_mesh_pt.resize(n_polyline);
35637 
35638  // Are we eligible for re-distributing polyline segments between
35639  // polylines? We're not if any of the boundaries are associated
35640  // with a GeomObject because we're then tied to the start and
35641  // end coordinates along it.
35642  bool eligible_for_segment_redistribution=true;
35643 
35644  // Loop over constituent polylines
35645  for(unsigned p=0;p<n_polyline;p++)
35646  {
35647 
35648  //Get the boundary id of the polyline
35649  unsigned bound =
35650  polygon_pt->polyline_pt(p)->boundary_id();
35651 
35652  //If the boundary has a geometric object representation then
35653  //we can't redistribute
35654  GeomObject* const geom_object_pt =
35655  this->boundary_geom_object_pt(bound);
35656  if(geom_object_pt!=0)
35657  {
35658  eligible_for_segment_redistribution=false;
35659  }
35660 
35661  face_mesh_pt[p] = new Mesh();
35662  create_unsorted_face_mesh_representation(
35663  bound, face_mesh_pt[p]);
35664 
35665  }
35666 
35667  if (!polygon_pt->is_redistribution_of_segments_between_polylines_enabled())
35668  {
35669  return;
35670  }
35671 
35672  //If there is more than one region we have to think... Die for now.
35673  if(this->nregion() > 1)
35674  {
35675  std::ostringstream warn_message;
35676  warn_message
35677  << "Can't currently re-distribute segments between polylines if there\n"
35678  << "are multiple regions; returning..." << std::endl;
35679  OomphLibWarning(warn_message.str(),
35680  "RefineableTriangleMesh::get_face_mesh_representation()",
35681  OOMPH_EXCEPTION_LOCATION);
35682  return;
35683  }
35684 
35685  // Redistribution overruled
35686  if (!eligible_for_segment_redistribution)
35687  {
35688  std::ostringstream warn_message;
35689  warn_message
35690  << "Over-ruling re-distribution of segments between polylines\n"
35691  << "because at least one boundary is associated with a GeomObject."
35692  << "Returning..." << std::endl;
35693  OomphLibWarning(warn_message.str(),
35694  "RefineableTriangleMesh::get_face_mesh_representation()",
35695  OOMPH_EXCEPTION_LOCATION);
35696  return;
35697  }
35698 
35699  // Create a vector for ordered face mesh
35700  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35701 
35702  // Storage for the total arclength of polygon
35703  double s_total=0.0;
35704 
35705  // Storage for first and last nodes on polylines so we can figure
35706  // out if they are inverted relative to each other
35707  Vector<Node*> first_polyline_node_pt(n_polyline);
35708  Vector<Node*> last_polyline_node_pt(n_polyline);
35709  std::vector<bool> is_reversed(n_polyline,false);
35710 
35711  // Loop over constituent polylines
35712  for(unsigned p=0;p<n_polyline;p++)
35713  {
35714 
35715  // Put all face elements in order
35716  //-------------------------------
35717 
35718  // Put first element into ordered list
35719  std::list<FiniteElement*> ordered_el_pt;
35720  FiniteElement* el_pt=face_mesh_pt[p]->finite_element_pt(0);
35721  ordered_el_pt.push_back(el_pt);
35722 
35723  // Number of nodes
35724  unsigned nnod=el_pt->nnode();
35725 
35726  // Default for first and last node on polyline
35727  first_polyline_node_pt[p]=el_pt->node_pt(0);
35728  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35729 
35730  // Count elements that have been done
35731  unsigned count_done=0;
35732 
35733  // How many face elements are there?
35734  unsigned n_face_element = face_mesh_pt[p]->nelement();
35735 
35736  //Get the boundary id of the polyline
35737  unsigned bound =
35738  polygon_pt->polyline_pt(p)->boundary_id();
35739 
35740  // Keep track of who's done
35741  std::map<FiniteElement*,bool> done_el;
35742 
35743  // Keep track of which element is inverted
35744  std::map<FiniteElement*,bool> is_inverted;
35745 
35746  // Fit in the other elements in at most nel^2 loops
35747  for (unsigned ee=1;ee<n_face_element;ee++)
35748  {
35749  // Loop over all elements to check if they fit to the right
35750  // or the left of the current one
35751  for (unsigned e=1;e<n_face_element;e++)
35752  {
35753  // Candidate element
35754  el_pt=face_mesh_pt[p]->finite_element_pt(e);
35755 
35756  // Is it done yet?
35757  if (!done_el[el_pt])
35758  {
35759  // Left and rightmost elements
35760  FiniteElement* first_el_pt=(*ordered_el_pt.begin());
35761  std::list<FiniteElement*>::iterator it=ordered_el_pt.end();
35762  it--;
35763  FiniteElement* last_el_pt=*it;
35764 
35765  // Left and rightmost nodes
35766  Node* left_node_pt=first_el_pt->node_pt(0);
35767  if (is_inverted[first_el_pt])
35768  {
35769  left_node_pt=first_el_pt->node_pt(nnod-1);
35770  }
35771  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35772  if (is_inverted[last_el_pt])
35773  {
35774  right_node_pt=last_el_pt->node_pt(0);
35775  }
35776 
35777  // New element fits at the left of first element and is not inverted
35778  if (left_node_pt==el_pt->node_pt(nnod-1))
35779  {
35780  ordered_el_pt.push_front(el_pt);
35781  done_el[el_pt]=true;
35782  count_done++;
35783  is_inverted[el_pt]=false;
35784  first_polyline_node_pt[p]=el_pt->node_pt(0);
35785  }
35786  // New element fits at the left of first element and is inverted
35787 
35788  else if (left_node_pt==el_pt->node_pt(0))
35789  {
35790  ordered_el_pt.push_front(el_pt);
35791  done_el[el_pt]=true;
35792  count_done++;
35793  is_inverted[el_pt]=true;
35794  first_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35795  }
35796  // New element fits on the right of last element and is not inverted
35797 
35798  else if(right_node_pt==el_pt->node_pt(0))
35799  {
35800  ordered_el_pt.push_back(el_pt);
35801  done_el[el_pt]=true;
35802  count_done++;
35803  is_inverted[el_pt]=false;
35804  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35805  }
35806  // New element fits on the right of last element and is inverted
35807 
35808  else if (right_node_pt==el_pt->node_pt(nnod-1))
35809  {
35810  ordered_el_pt.push_back(el_pt);
35811  done_el[el_pt]=true;
35812  count_done++;
35813  is_inverted[el_pt]=true;
35814  last_polyline_node_pt[p]=el_pt->node_pt(0);
35815  }
35816 
35817  if (done_el[el_pt])
35818  {
35819  break;
35820  }
35821  }
35822  }
35823  }
35824 
35825  // Are we done?
35826  if (count_done!=(n_face_element-1))
35827  {
35828  std::ostringstream error_message;
35829  error_message
35830  << "When ordering FaceElements on "
35831  << "boundary " << bound << " only managed to order \n" << count_done
35832  << " of " << n_face_element << " face elements.\n"
35833  << std::endl;
35834  throw OomphLibError(
35835  error_message.str(),
35836  OOMPH_CURRENT_FUNCTION,
35837  OOMPH_EXCEPTION_LOCATION);
35838  }
35839 
35840  // Now make a mesh that contains the FaceElements in order
35841  ordered_face_mesh_pt[p] = new Mesh;
35842 
35843  // Fill it
35844  for (std::list<FiniteElement*>::iterator it=ordered_el_pt.begin();
35845  it!=ordered_el_pt.end();it++)
35846  {
35847  // Get element
35848  FiniteElement* el_pt=*it;
35849 
35850  // add this face element to the order original mesh
35851  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
35852  }
35853 
35854  //Get the arclength along the polygon
35855  for(unsigned e=0;e<n_face_element;++e)
35856  {
35857  FiniteElement* el_pt=ordered_face_mesh_pt[p]->finite_element_pt(e);
35858  unsigned n_node=el_pt->nnode();
35859  double element_length_squared=0.0;
35860  for(unsigned i=0;i<2;i++)
35861  {
35862  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
35863  el_pt->node_pt(0)->x(i),2);
35864  }
35865 
35866  // Determine element length
35867  double element_length=sqrt(element_length_squared);
35868 
35869  // Add this length to the total arclength
35870  s_total += element_length;
35871  }
35872 
35873  // Empty the original meshes
35874  face_mesh_pt[p]->flush_element_and_node_storage();
35875  }
35876 
35877  // Is first one reversed?
35878  if ((last_polyline_node_pt[0]==first_polyline_node_pt[1])||
35879  (last_polyline_node_pt[0]==last_polyline_node_pt[1]))
35880  {
35881  is_reversed[0]=false;
35882  }
35883  else if ((first_polyline_node_pt[0]==first_polyline_node_pt[1])||
35884  (first_polyline_node_pt[0]==last_polyline_node_pt[1]))
35885  {
35886  is_reversed[0]=true;
35887  }
35888 
35889  // Reorder the face meshes so that they are contiguous
35890  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
35891  std::vector<bool> mesh_done(n_polyline,false);
35892  Vector<unsigned> old_polyline_number(n_polyline);
35893 
35894  // Initial entry
35895  tmp_face_mesh_pt[0]=ordered_face_mesh_pt[0];
35896  unsigned current=0;
35897  old_polyline_number[0]=0;
35898  unsigned count_found=0;
35899 
35900  // Fill in the next entries
35901  for(unsigned p=1;p<n_polyline;p++)
35902  {
35903  Node* end_node_pt=last_polyline_node_pt[current];
35904  if (is_reversed[current])
35905  {
35906  end_node_pt=first_polyline_node_pt[current];
35907  }
35908 
35909  // Loop over all remaining face meshes to see which one fits
35910  for(unsigned pp=1;pp<n_polyline;pp++)
35911  {
35912  if (!mesh_done[pp])
35913  {
35914  // Current one is not reversed, candidate is not reversed
35915  if ((!is_reversed[current])&&
35916  (end_node_pt==first_polyline_node_pt[pp]))
35917  {
35918  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35919  mesh_done[pp]=true;
35920  is_reversed[pp]=false;
35921  old_polyline_number[p]=pp;
35922  current=pp;
35923  count_found++;
35924  break;
35925  }
35926  // Current one is not reversed, candidate is reversed
35927 
35928  else if ((!is_reversed[current])&&
35929  (end_node_pt==last_polyline_node_pt[pp]))
35930  {
35931  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35932  mesh_done[pp]=true;
35933  is_reversed[pp]=true;
35934  old_polyline_number[p]=pp;
35935  current=pp;
35936  count_found++;
35937  break;
35938  }
35939  // Current one is reversed, candidate is not reversed
35940 
35941  else if ((is_reversed[current])&&
35942  (end_node_pt==first_polyline_node_pt[pp]))
35943  {
35944  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35945  mesh_done[pp]=true;
35946  is_reversed[pp]=false;
35947  old_polyline_number[p]=pp;
35948  current=pp;
35949  count_found++;
35950  break;
35951  }
35952  // Current one is reversed, candidate is reversed
35953 
35954  else if ((is_reversed[current])&&
35955  (end_node_pt==last_polyline_node_pt[pp]))
35956  {
35957  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35958  mesh_done[pp]=true;
35959  is_reversed[pp]=true;
35960  old_polyline_number[p]=pp;
35961  current=pp;
35962  count_found++;
35963  break;
35964  }
35965  }
35966  }
35967  }
35968 
35969 #ifdef PARANOID
35970  if (count_found!=n_polyline-1)
35971  {
35972  std::ostringstream error_message;
35973  error_message << "Only found " << count_found
35974  << " out of " << n_polyline-1
35975  << " polylines to be fitted in.\n";
35976  throw OomphLibError(
35977  error_message.str(),
35978  OOMPH_CURRENT_FUNCTION,
35979  OOMPH_EXCEPTION_LOCATION);
35980  }
35981 #endif
35982 
35983  // Now overwrite the re-ordered data
35984  for (unsigned i=0;i<n_polyline;i++)
35985  {
35986  ordered_face_mesh_pt[i]=tmp_face_mesh_pt[i];
35987  }
35988 
35989  // Now do an approximate equidistribution of polylines
35990  //----------------------------------------------------
35991  double s=0.0;
35992  unsigned new_face_id=0;
35993 
35994  // Matrix map to indicate if node must not be removed from specified
35995  // boundary (!=0) or not (=0). Initialises itself to zero
35996  std::map<Node*,std::map<unsigned,unsigned> >
35997  node_must_not_be_removed_from_boundary_flag;
35998 
35999  // Loop over the old face mesh
36000  for(unsigned p=0;p<n_polyline;p++)
36001  {
36002  // Loop over the face elements
36003  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36004  for (unsigned e=0;e<n_face_element;e++)
36005  {
36006  unsigned el_number=e;
36007  if (is_reversed[p])
36008  {
36009  el_number=n_face_element-e-1;
36010  }
36011 
36012  FiniteElement* el_pt=
36013  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36014  unsigned n_node = el_pt->nnode();
36015 
36016  // Determine element length
36017  double element_length_squared=0.0;
36018  for(unsigned i=0;i<2;i++)
36019  {
36020  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
36021  el_pt->node_pt(0)->x(i),2);
36022  }
36023  double element_length=sqrt(element_length_squared);
36024 
36025  // Add this length to the total arclength
36026  s += element_length;
36027 
36028  // Check if the current 'arclength' is less than the
36029  // whole 'arclength' divided by the number of polylines
36030  if(s < s_total/double(n_polyline)+1e-6)
36031  {
36032  // If so add this face element to the new face mesh
36033  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36034 
36035  unsigned bound_old =
36036  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36037 
36038  unsigned bound_new =
36039  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36040 
36041  // Loop over the nodes in the element
36042  for(unsigned i=0;i<n_node;i++)
36043  {
36044  // Get the pointer to the node
36045  Node* nod_pt=el_pt->node_pt(i);
36046 
36047  // If the two boundary id's are different, the face element's nodes
36048  // have to be added to the new boundary
36049  if(bound_new != bound_old)
36050  {
36051  // Add it to the new boundary
36052  add_boundary_node(bound_new,nod_pt);
36053 
36054  // We are happy for this node to be removed from the
36055  // old boundary?
36056  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=0;
36057  }
36058 
36059  // If the face element hasn't moved, its nodes MUST remain
36060  // on that boundary (incl. any nodes that ar shared by
36061  // FaceElements that have moved (see above)
36062 
36063  else
36064  {
36065  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=1;
36066  }
36067  }
36068  }
36069 
36070  // If not, reset the current 'arclength' to zero,
36071  // increase the new face id by one and go one element
36072  // back by decreasing e by one to make sure the current
36073  // element gets added to the next face mesh
36074 
36075  else
36076  {
36077  if(new_face_id!=n_polyline-1)
36078  {
36079  s=0.0;
36080  new_face_id++;
36081  --e;
36082  }
36083  else
36084  {
36085  s=0.0;
36086  --e;
36087  }
36088  }
36089  }
36090  } // end of loop over all polylines -- they are now re-distributed
36091 
36092 
36093  // Loop over all nodes on the boundaries of the polygon to remove
36094  // nodes from boundaries they are no longer on
36095  unsigned move_count=0;
36096  for (std::map<Node*,std::map<unsigned,unsigned> >::iterator
36097  it=node_must_not_be_removed_from_boundary_flag.begin();
36098  it!=node_must_not_be_removed_from_boundary_flag.end();it++)
36099  {
36100  // Get the node
36101  Node* nod_pt=(*it).first;
36102 
36103  // Now we loop over the boundaries that this node is on
36104  for (std::map<unsigned,unsigned>::iterator
36105  it_2=(*it).second.begin();it_2!=(*it).second.end();it_2++)
36106  {
36107  // Get the boundary id
36108  unsigned bound=(*it_2).first;
36109 
36110  // Remove it from that boundary?
36111  if((*it_2).second==0)
36112  {
36113  remove_boundary_node(bound,nod_pt);
36114  move_count++;
36115  }
36116  }
36117  }
36118 
36119  // Loop over the new face mesh to assign new boundary IDs
36120  for(unsigned p=0;p<n_polyline;p++)
36121  {
36122  //Get the boundary id of the polyline
36123  unsigned bound =
36124  polygon_pt->polyline_pt(p)->boundary_id();
36125 
36126  // Loop over the face elements
36127  unsigned n_face_element = face_mesh_pt[p]->nelement();
36128  for(unsigned e=0;e<n_face_element;e++)
36129  {
36130  //Cast the element pointer to the correct thing!
36131  FaceElementAsGeomObject<ELEMENT>* el_pt=
36132  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
36133  (face_mesh_pt[p]->element_pt(e));
36134 
36135  // Set bulk boundary number
36136  el_pt->set_boundary_number_in_bulk_mesh(bound);
36137  }
36138  }
36139 
36140  // Update look-up for elements next to boundary
36141  setup_boundary_element_info();
36142 
36143  // Now re-create the boundary coordinates
36144  for(unsigned p=0;p<n_polyline;p++)
36145  {
36146  //Get the boundary id of the polyline
36147  unsigned bound =
36148  polygon_pt->polyline_pt(p)->boundary_id();
36149 
36150  // Do it
36151  this->template setup_boundary_coordinates<ELEMENT>(bound);
36152  }
36153 
36154  // Clean up
36155  for(unsigned p=0;p<n_polyline;p++)
36156  {
36157  // Flush the nodes from the face mesh to make sure we
36158  // don't delete them (the face mesh that we're returning from here
36159  // still needs them!)
36160  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36161  delete ordered_face_mesh_pt[p];
36162  }
36163 
36164  }
36165 
36166 //=========================================================================
36167 /// Helper function to construct face mesh representation of all polylines
36168 //=========================================================================
36169 template<class ELEMENT>
36172  TriangleMeshOpenCurve* open_polyline_pt,
36173  Vector<Mesh*>& face_mesh_pt)
36174 {
36175  // Number of polylines
36176  unsigned n_polyline = open_polyline_pt->ncurve_section();
36177  face_mesh_pt.resize(n_polyline);
36178 
36179  // Loop over constituent polylines
36180  for(unsigned p=0;p<n_polyline;p++)
36181  {
36182 
36183  //Get the boundary id of the polyline
36184  unsigned bound =
36185  open_polyline_pt->curve_section_pt(p)->boundary_id();
36186 
36187  face_mesh_pt[p] = new Mesh();
36188  create_unsorted_face_mesh_representation(
36189  bound, face_mesh_pt[p]);
36190 
36191  }
36192 
36193 }
36194 
36195 //======================================================================
36196 /// Update the PSLG that define the inner boundaries of the mesh.
36197 ///Optional boolean is used to run it as test only (if
36198 /// true is specified as input) in which case PSLG isn't actually
36199 /// modified. Returned boolean indicates if PSLG was (or would have
36200 /// been -- if called with check_only=false) changed.
36201 //======================================================================
36202 template <class ELEMENT>
36205  &internal_point_coord,
36206  const bool& check_only)
36207  {
36208  //Boolean to indicate whether an actual update of the internal
36209  // holes was performed
36210  bool update_was_performed=false;
36211  //Loop over the number of internal boundaries
36212  unsigned n_hole = internal_point_coord.size();
36213  for(unsigned ihole=0;ihole<n_hole;ihole++)
36214  {
36215  //Cache the pointer to the polygon representation
36216  TriangleMeshPolygon* const poly_pt
36217  = this->Internal_polygon_pt[ihole];
36218 
36219 
36220  //Can the polygon update its own configuration, in which case this
36221  //is easy
36222  if(poly_pt->can_update_reference_configuration())
36223  {
36224  poly_pt->reset_reference_configuration();
36225 
36226  // Initialize Vector hole_coordinates
36227  internal_point_coord[ihole].resize(2);
36228 
36229  // Get the vector of hole coordinates
36230  internal_point_coord[ihole]=poly_pt->internal_point();
36231  }
36232  //Otherwise we have to work much harder
36233 
36234  else
36235  {
36236  //if we only want to check whether an update of the inner
36237  //hole is necessary
36238  if(check_only)
36239  {
36240  //is it necessary?
36241  bool update_necessary=
36242  this->update_polygon_using_face_mesh(poly_pt,check_only);
36243 
36244  //Yes?
36245  if(update_necessary)
36246  {
36247  //then we have to adaptand return 'true'
36248  return true;
36249  }
36250  }
36251  //if we not only want to check, then we actually perform
36252  //the update
36253  else
36254  {
36255  update_was_performed=
36256  this->update_polygon_using_face_mesh(poly_pt);
36257  }
36258 
36259  //Now we need to sort out the hole coordinates
36260  if (!poly_pt->internal_point().empty())
36261  {
36262  //If fixed don't update and simply
36263  //Read out the existing value
36264  if(poly_pt->is_internal_point_fixed())
36265  {
36266  // Get the vector of hole coordinates
36267  internal_point_coord[ihole]=poly_pt->internal_point();
36268  }
36269  //This is where the work starts and this could be made much
36270  //better than the current hack
36271  else
36272  {
36273  //If the user has set their own function then use that
36274  if(this->Internal_hole_point_update_fct_pt!=0)
36275  {
36276  this->Internal_hole_point_update_fct_pt(ihole,poly_pt);
36277  }
36278  //Otherwise use our clunky default
36279  else
36280  {
36281  //Now sort out the hole coordinates
36282  Vector<double> vertex_coord;
36283  unsigned n_polyline = poly_pt->npolyline();
36284 
36285  // Initialize Vector hole_coordinates
36286  vertex_coord.resize(2);
36287  internal_point_coord[ihole].resize(2);
36288 
36289  //Hole centre will be found by averaging the position of
36290  //all vertex nodes
36291  internal_point_coord[ihole][0] = 0.0;
36292  internal_point_coord[ihole][1] = 0.0;
36293 
36294  for(unsigned p=0;p<n_polyline;p++)
36295  {
36296  Vector<double> poly_ave(2,0.0);
36297  //How many vertices are there in the segment
36298  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36299  for(unsigned v=0;v<n_vertex;v++)
36300  {
36301  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36302  for(unsigned i=0;i<2;i++)
36303  {
36304  poly_ave[i] += vertex_coord[i];
36305  }
36306  }
36307 
36308  //Add the average polyline coordinate to the hole centre
36309  for(unsigned i=0;i<2;i++)
36310  {
36311  internal_point_coord[ihole][i] += poly_ave[i]/n_vertex;
36312  }
36313  }
36314 
36315  //Now average out the hole centre
36316  for(unsigned i=0;i<2;i++)
36317  {
36318  internal_point_coord[ihole][i] /= n_polyline;
36319  }
36320 
36321  //We have now found the hole centre stored in internal_point_coordinate[ihole][i]
36322 
36323  //Find polylines that intersect at y average value
36324  //Alice's version but this does not work if the end point of a
36325  //segment is the intersection point (i.e. at the y average value)
36326  /*Vector<double> vertex_coord2;
36327  unsigned n_intersect=0;
36328  double x_average=0.0;
36329 
36330  for(unsigned p=0;p<n_polyline;p++)
36331  {
36332  //How many vertices are there in the segment
36333  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36334  for(unsigned v=0;v<n_vertex-1;v++)
36335  {
36336  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36337  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36338  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36339  << " " <<
36340  vertex_coord2[0] << " " <<
36341 
36342  vertex_coord2[1] << "\n";
36343  //Does the line between vertices intersect the vertical position
36344  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36345  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36346  {
36347  ++n_intersect; x_average += 0.5*(vertex_coord[0] + vertex_coord2[0]);
36348  }
36349  }
36350  }
36351 
36352  //Now just report the value if we have had intersections
36353  if(n_intersect != 0)
36354  {
36355  //Report
36356  std::cout << "I have computed a hole " << x_average << " " << n_intersect << " "
36357  << x_average/((double)n_intersect) << std::endl;
36358  internal_point_coord[ihole][0] = x_average/((double)n_intersect);
36359  }
36360  */
36361 
36362  //Set the new hole centre
36363  poly_pt->internal_point() = internal_point_coord[ihole];
36364  //std::cout << "I've had my centre updated to "
36365  // << internal_point_coord[ihole][0]
36366  // << " " << internal_point_coord[ihole][1] << "\n";
36367  }
36368  }
36369 
36370  }
36371  }
36372  } //End of the action (n_hole for)
36373 
36374  if(check_only)
36375  {
36376  // If we make it up to here and we only check then no update is required
36377  return false;
36378  }
36379  else
36380  {
36381  // otherwise indicate whether an actual update was performed
36382  return update_was_performed;
36383  }
36384 
36385  } //End of the loop of internal boundaries
36386 
36387  //======================================================================
36388  /// Create the polylines and fill associate data structures, used when
36389  /// creating from a mesh from polyfiles
36390  //======================================================================
36391  template<class ELEMENT>
36393  create_polylines_from_polyfiles(const std::string& node_file_name,
36394  const std::string& poly_file_name)
36395  {
36396  // Get the nodes coordinates (the index of the nodes to build the
36397  // polylines is the one used in the node_file_name file)
36398  // Process node file
36399  // -----------------
36400  std::ifstream node_file(node_file_name.c_str(),std::ios_base::in);
36401 
36402  // Check that the file actually opened correctly
36403  if(!node_file.is_open())
36404  {
36405  std::string error_msg("Failed to open node file: ");
36406  error_msg += "\"" + node_file_name + "\".";
36407  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36408  OOMPH_EXCEPTION_LOCATION);
36409  }
36410 
36411  // Read number of nodes
36412  unsigned nnodes;
36413  node_file >> nnodes;
36414 
36415  // Spatial dimension of nodes
36416  unsigned dimension;
36417  node_file >> dimension;
36418 
36419 #ifdef PARANOID
36420  if(dimension!=2)
36421  {
36422  throw OomphLibError("The dimension must be 2\n",
36423  OOMPH_CURRENT_FUNCTION,
36424  OOMPH_EXCEPTION_LOCATION);
36425  }
36426 #endif
36427 
36428  // Storage the nodes vertices
36429  Vector<double> x_node(nnodes);
36430  Vector<double> y_node(nnodes);
36431 
36432  // Number of attributes
36433  unsigned npoint_attributes;
36434  node_file >> npoint_attributes;;
36435 
36436  // Flag for boundary markers
36437  unsigned boundary_markers_flag=0;
36438  node_file >> boundary_markers_flag;
36439 
36440  // Dummy for node number
36441  unsigned dummy_node_number;
36442  // Dummy for node attribute
36443  unsigned dummy_node_attribute;
36444  // Dummy for node boundary
36445  unsigned dummy_node_boundary;
36446 
36447  // Load in nodal posititions, point attributes
36448  // and boundary markers
36449  for(unsigned i=0;i<nnodes;i++)
36450  {
36451  node_file>>dummy_node_number;
36452  node_file>>x_node[i];
36453  node_file>>y_node[i];
36454  for(unsigned j=0;j<npoint_attributes;++j)
36455  {
36456  node_file>>dummy_node_attribute;
36457  }
36458  if(boundary_markers_flag)
36459  {
36460  node_file>>dummy_node_boundary;
36461  }
36462  }
36463  node_file.close();
36464 
36465  // Get the segments information and use that info. to create the
36466  // polylines
36467 
36468  // A map to store the segments associated to a boundary, non sorted
36469  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >
36470  unsorted_boundary_segments;
36471 
36472  // Independent storage for the boundaries ids found in the segments so that
36473  // the polylines, and therefore polygons be created in the order they appear
36474  // in the polyfile
36475  Vector<unsigned> sorted_boundaries_ids;
36476 
36477  // Process poly file to extract edges
36478  //-----------------------------------
36479 
36480  // Open poly file
36481  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
36482 
36483  // Check that the file actually opened correctly
36484  if(!poly_file.is_open())
36485  {
36486  std::string error_msg("Failed to open poly file: ");
36487  error_msg += "\"" + poly_file_name + "\".";
36488  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36489  OOMPH_EXCEPTION_LOCATION);
36490  }
36491 
36492  // Number of nodes in poly file --- these will be ignore
36493  unsigned n_node_poly;
36494  poly_file >> n_node_poly;
36495 
36496  // Dimension
36497  poly_file >> dimension;
36498 
36499  // Attribute flag
36500  unsigned attribute_flag;
36501  poly_file >> attribute_flag;
36502 
36503  // Flag for boundary markers
36504  poly_file >> boundary_markers_flag;
36505 
36506  // Ignore node information: Note: No, we can't extract the
36507  // actual nodes themselves from here!
36508  unsigned dummy;
36509  for(unsigned i=0;i<n_node_poly;i++)
36510  {
36511  //Read in (and discard) node number and x and y coordinates
36512  poly_file>>dummy;
36513  poly_file>>dummy;
36514  poly_file>>dummy;
36515  //read in the attributes
36516  for(unsigned j=0;j<attribute_flag;++j)
36517  {
36518  poly_file >> dummy;
36519  }
36520  //read in the boundary marker
36521  if(boundary_markers_flag==1)
36522  {
36523  poly_file>>dummy;
36524  }
36525  }
36526 
36527  // Variable used to read the values from the input file
36528  unsigned read_value;
36529 
36530  // Number of segments
36531  poly_file >> read_value;
36532  const unsigned nglobal_segments = read_value;
36533 
36534  // Boundary marker flag
36535  poly_file >> boundary_markers_flag;
36536 
36537  // Global segment number
36538  unsigned global_segment_number;
36539 
36540  // Node identifier set (used to identify possible internal boundaries)
36541  std::set<unsigned> nodes_ids;
36542 
36543  // Extract information for each segment
36544  for(unsigned i=0;i<nglobal_segments;i++)
36545  {
36546  // Node id on the edge of the segment
36547  unsigned lnode_id=0; // left node
36548  unsigned rnode_id=0; // right node
36549  unsigned bnd_id=0; // boundary id associated to the current segment
36550  poly_file >> global_segment_number;
36551  poly_file >> lnode_id;
36552  poly_file >> rnode_id;
36553  nodes_ids.insert(lnode_id);
36554  nodes_ids.insert(rnode_id);
36555  if(boundary_markers_flag)
36556  {
36557  poly_file >> bnd_id;
36558  }
36559 
36560  // Store the segments info. (use bnd_id - 1 because the nodes and
36561  // elements associated the bnd_id have been associated by external
36562  // methods to bnd_id - 1)
36563  unsorted_boundary_segments[bnd_id-1].push_back(
36564  std::make_pair(lnode_id, rnode_id));
36565 
36566  // Add the boundary id to the vector of boundaries ids only if it
36567  // has not been added, the polylines will be created using this
36568  // order
36569 
36570  // Get the number of boundaries ids currently sorted
36571  const unsigned nsorted_boundaries_ids =
36572  sorted_boundaries_ids.size();
36573  // Flag to know if the boundary id was found
36574  bool boundary_id_found = false;
36575  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36576  {
36577  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36578  {
36579  boundary_id_found = true;
36580  break;
36581  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36582  } // for (ib < nsorted_boundaries_ids)
36583 
36584  // If th boundary id has not been added, then add it!!!
36585  if (!boundary_id_found)
36586  {
36587  sorted_boundaries_ids.push_back(bnd_id - 1);
36588  } // if (!boundary_id_found)
36589 
36590  }
36591 
36592  // Verify if there are internal boundaries defined, if that is the
36593  // case we can not continue since we are not yet supporting internal
36594  // boundaries defined in polyfiles to created a mesh that may be
36595  // adapted
36596 #ifdef PARANOID
36597  if (nglobal_segments != nodes_ids.size())
36598  {
36599  std::ostringstream error_message;
36600  error_message
36601  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36602  << nglobal_segments << ") is different.\nThis may mean that there "
36603  << "are internal non-closed boundaries defined in\nthe polyfile. "
36604  << "If you need this feature please use the TriangleMeshPoyLine\n"
36605  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36606  throw OomphLibError(error_message.str(),
36607  OOMPH_CURRENT_FUNCTION,
36608  OOMPH_EXCEPTION_LOCATION);
36609  }
36610 #endif
36611 
36612  // Now sort the segments associated to a boundary to create a contiguous
36613  // polyline, but first check that the number of found boundaries be the
36614  // same as the current number of boundaries in the mesh
36615  const unsigned nboundary = unsorted_boundary_segments.size();
36616 
36617 #ifdef PARANOID
36618  if (nboundary != this->nboundary())
36619  {
36620  std::ostringstream error_message;
36621  error_message
36622  << "The number of boundaries on the mesh (" << this->nboundary()
36623  << ") is different from the number of\nboundaries read from the "
36624  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36625  throw OomphLibError(error_message.str(),
36626  OOMPH_CURRENT_FUNCTION,
36627  OOMPH_EXCEPTION_LOCATION);
36628  }
36629 #endif
36630 
36631  // Get the number of sorted boundaries ids and check that it matches
36632  // with the total number of boundaries
36633  const unsigned nsorted_boundaries_ids =
36634  sorted_boundaries_ids.size();
36635 #ifdef PARANOID
36636  if (nsorted_boundaries_ids != this->nboundary())
36637  {
36638  std::ostringstream error_message;
36639  error_message
36640  << "The number of boundaries on the mesh (" << this->nboundary()
36641  << ") is different from the number of\nsorted boundaries ids read "
36642  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36643  throw OomphLibError(error_message.str(),
36644  OOMPH_CURRENT_FUNCTION,
36645  OOMPH_EXCEPTION_LOCATION);
36646  }
36647 #endif
36648 
36649  // Sorted segments (to create a polyline -- boundary)
36650  std::map<unsigned, std::list<unsigned> > sorted_boundary_segments;
36651 
36652  // Go through all the found boundaries
36653  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >::iterator it;
36654 
36655  for (it = unsorted_boundary_segments.begin();
36656  it != unsorted_boundary_segments.end();
36657  it++)
36658  {
36659  // Get the current boundary id, only look for the segments
36660  // associated with this boundary
36661  const unsigned bnd_id = (*it).first;
36662  Vector<std::pair<unsigned, unsigned> > segments_edges = (*it).second;
36663 
36664  // Now sort the segments associated to this boundary
36665  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36666  const unsigned nsegments = segments_edges.size();
36667 
36668  // Sorted nodes for the current segment
36669  std::list<unsigned> sorted_segments;
36670 
36671  // Get the left and right node of the zero segment
36672  unsigned left_node_id = segments_edges[0].first;
36673  unsigned right_node_id = segments_edges[0].second;
36674 
36675  // ... and add it to the sorted segments structure
36676  sorted_segments.push_back(left_node_id);
36677  sorted_segments.push_back(right_node_id);
36678 
36679  // Mark the current segment as done
36680  segment_done[segments_edges[0]] = true;
36681 
36682  // Set the number of sorted segments
36683  unsigned nsorted_segments = 1;
36684 
36685  while(nsorted_segments < nsegments)
36686  {
36687  for (unsigned i = 1; i < nsegments; i++)
36688  {
36689  // Check if the i-th segments has been done
36690  if (!segment_done[segments_edges[i]])
36691  {
36692  // Get the left and right node id
36693  unsigned current_left_node_id = segments_edges[i].first;
36694  unsigned current_right_node_id = segments_edges[i].second;
36695 
36696  // Now check if the current segment can be added to the left
36697  // or right side of the sorted segments
36698  if (current_left_node_id == right_node_id)
36699  {
36700  // Add the current_right_node_id to the right of the sorted
36701  // segments
36702  sorted_segments.push_back(current_right_node_id);
36703  // Increase the number of sorted segments
36704  nsorted_segments++;
36705  // Mark the segment as done
36706  segment_done[segments_edges[i]] = true;
36707  // Update the right most node
36708  right_node_id = current_right_node_id;
36709  // Break the for loop
36710  break;
36711  }
36712  else if (current_right_node_id == left_node_id)
36713  {
36714  // Add the current_left_node_id to the left of the sorted
36715  // segments
36716  sorted_segments.push_front(current_left_node_id);
36717  // Increase the number of sorted segments
36718  nsorted_segments++;
36719  // Mark the segment as done
36720  segment_done[segments_edges[i]] = true;
36721  // Update the left most node
36722  left_node_id = current_left_node_id;
36723  // Break the for loop
36724  break;
36725  }
36726  else if (current_left_node_id == left_node_id)
36727  {
36728  // Add the current_right_node_id to the left of the sorted
36729  // segments
36730  sorted_segments.push_front(current_right_node_id);
36731  // Increase the number of sorted segments
36732  nsorted_segments++;
36733  // Mark the segment as done
36734  segment_done[segments_edges[i]] = true;
36735  // Update the left most node
36736  left_node_id = current_right_node_id;
36737  // Break the for loop
36738  break;
36739  }
36740  else if (current_right_node_id == right_node_id)
36741  {
36742  // Add the current_left_node_id to the right of the sorted
36743  // segments
36744  sorted_segments.push_back(current_left_node_id);
36745  // Increase the number of sorted segments
36746  nsorted_segments++;
36747  // Mark the segment as done
36748  segment_done[segments_edges[i]] = true;
36749  // Update the left most node
36750  right_node_id = current_left_node_id;
36751  // Break the for loop
36752  break;
36753  }
36754  } // if (!segment_done[segments_edges[i]])
36755  } // for (i < nsegments)
36756  } // while(nsorted_segments < nsegments)
36757 
36758  sorted_boundary_segments[bnd_id] = sorted_segments;
36759 
36760  } // for (unsorted_boundary_segments.begin();
36761  // unsorted_boundary_segments.end())
36762 
36763 #ifdef PARANOID
36764  if (sorted_boundary_segments.size() != this->nboundary())
36765  {
36766  std::ostringstream error_message;
36767  error_message
36768  << "The number of boundaries on the mesh (" << this->nboundary()
36769  << ") is different from the number\nof sorted boundaries to create the "
36770  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
36771  throw OomphLibError(error_message.str(),
36772  OOMPH_CURRENT_FUNCTION,
36773  OOMPH_EXCEPTION_LOCATION);
36774  }
36775 #endif
36776 
36777  // Now we have the sorted nodes, we can create the polylines by
36778  // getting the vertices of the nodes
36779  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
36780  unsigned current_polyline = 0;
36781 
36782  // Go through the sorted boundaries using the sorted boundaries ids
36783  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36784  {
36785  // Get the boundary id from the vector of sorted boundaries ids
36786  const unsigned bnd_id = sorted_boundaries_ids[ib];
36787 
36788  // Create a vector representation for ease to use
36789  // Get the vertices of the nodes that create the boundary / polyline
36790  Vector<unsigned> nodes_ids;
36791  for (std::list<unsigned>::iterator it_list =
36792  sorted_boundary_segments[bnd_id].begin();
36793  it_list != sorted_boundary_segments[bnd_id].end();
36794  it_list++)
36795  {nodes_ids.push_back((*it_list));}
36796 
36797  // Get the number of vertices for the polyline
36798  const unsigned nvertices = nodes_ids.size();
36799 
36800  // The storage for the vertices
36801  Vector<Vector<double> > vertices(nvertices);
36802 
36803  // Now get the vertices of the nodes of the current boundary
36804  for (unsigned i = 0; i < nvertices; i++)
36805  {
36806  // Get the vertices
36807  vertices[i].resize(2);
36808  vertices[i][0] = x_node[nodes_ids[i]-1];
36809  vertices[i][1] = y_node[nodes_ids[i]-1];
36810  }
36811 
36812  // Now create the polyline
36813 
36814  // Note: The bnd_id is the real bnd_id (from the input file) - 1
36815  // since nodes and elements of the current boundary have been
36816  // associated to bnd_id - 1)
36817  polylines_pt[current_polyline] =
36818  new TriangleMeshPolyLine(vertices, bnd_id);
36819 
36820  // Updates bnd_id<--->curve section map
36821  this->Boundary_curve_section_pt[bnd_id] =
36822  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
36823 
36824  // Increase the index for the polyline storage
36825  current_polyline++;
36826 
36827  } // for (it_sorted = sorted_boundary_segments.begin();
36828  // it_sorted != sorted_boundary_segments.end())
36829 
36830  // Now create the polygons or closed curves
36831  // Sort the polylines to create polygons
36832  unsigned nsorted_polylines = 0;
36833 
36834  // Number of created polygons
36835  unsigned npolygons = 0;
36836 
36837  // Storage for the polygons
36838  Vector<TriangleMeshPolygon*> polygons_pt;
36839 
36840  // Mark the already done polylines
36841  std::map<unsigned, bool> polyline_done;
36842  while(nsorted_polylines < nboundary)
36843  {
36844  // Storage for the curve sections that create a polygon
36845  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
36846 
36847  unsigned init_poly = 0;
36848 #ifdef PARANOID
36849  bool found_root_polyline = false;
36850 #endif
36851  // Get the left and right node of the current polyline
36852  for (unsigned i = 0; i < nboundary; i++)
36853  {
36854  if (!polyline_done[i])
36855  {
36856  init_poly = i;
36857  // Increase the number of sorted polylines
36858  nsorted_polylines++;
36859 #ifdef PARANOID
36860  // Mark as found the root polyline
36861  found_root_polyline = true;
36862 #endif
36863  // Mark the polyline as done
36864  polyline_done[i] = true;
36865  // Add the polyline to the curve sections storage
36866  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36867  // Break the loop to set we have found a root polyline
36868  break;
36869  }
36870  }
36871 
36872 #ifdef PARANOID
36873  if (!found_root_polyline)
36874  {
36875  std::ostringstream error_message;
36876  error_message
36877  << "Was not possible to found the root polyline to create polygons\n\n";
36878  throw OomphLibError(error_message.str(),
36879  OOMPH_CURRENT_FUNCTION,
36880  OOMPH_EXCEPTION_LOCATION);
36881  }
36882 #endif
36883 
36884  // Get the associated boundary to the current polyline
36885  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
36886  // Get the initial and final node id of the current polyline
36887  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
36888  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
36889 
36890  // Flag to know that we already have a closed polygon
36891  bool closed_polygon = false;
36892 
36893  do
36894  {
36895  // Go through all the polylines
36896  for (unsigned i = init_poly; i < nboundary; i++)
36897  {
36898  // Check that the polyline has not been currently done
36899  if (!polyline_done[i])
36900  {
36901  // Get the initial and final nodes id of the current polyline
36902 
36903  // Get the associated boundary to the current polyline
36904  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
36905  // Get the initial and final node id of the current polyline
36906  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
36907  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
36908 
36909  // Check if the polyline goes to the left or right of the
36910  // current sorted polylines
36911  if (cleft_node_id == right_node_id)
36912  {
36913  // Add the polyline to the curve section storage
36914  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36915  // Mark the polyline as done
36916  polyline_done[i] = true;
36917  // Update the right node
36918  right_node_id = cright_node_id;
36919  // Increase the number of done polyines
36920  nsorted_polylines++;
36921  // Break the for loop
36922  break;
36923  }
36924  else if (cright_node_id == left_node_id)
36925  {
36926  // Add the polyline to the curve section storage
36927  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36928  // Mark the polyline as done
36929  polyline_done[i] = true;
36930  // Update the right node
36931  left_node_id = cleft_node_id;
36932  // Increase the number of done polyines
36933  nsorted_polylines++;
36934  // Break the for loop
36935  break;
36936  }
36937  else if (cleft_node_id == left_node_id)
36938  {
36939  // First reverse the polyline
36940  polylines_pt[i]->reverse();
36941  // Add the polyline to the curve section storage
36942  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36943  // Mark the polyline as done
36944  polyline_done[i] = true;
36945  // Update the right node
36946  left_node_id = cright_node_id;
36947  // Increase the number of done polyines
36948  nsorted_polylines++;
36949  // Break the for loop
36950  break;
36951  }
36952  else if (cright_node_id == right_node_id)
36953  {
36954  // First reverse the polyline
36955  polylines_pt[i]->reverse();
36956  // Add the polyline to the curve section storage
36957  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36958  // Mark the polyline as done
36959  polyline_done[i] = true;
36960  // Update the right node
36961  right_node_id = cleft_node_id;
36962  // Increase the number of done polyines
36963  nsorted_polylines++;
36964  // Break the for loop
36965  break;
36966  }
36967  } // if (!polyline_done[i])
36968 
36969  } // for (i < nboundary)
36970 
36971  // We have created a polygon
36972  if (left_node_id == right_node_id)
36973  {
36974  // Set the flag as true
36975  closed_polygon = true;
36976  }
36977 
36978  }while(nsorted_polylines < nboundary && !closed_polygon);
36979 
36980 #ifdef PARANOID
36981  if (!closed_polygon)
36982  {
36983  std::ostringstream error_message;
36984  error_message
36985  << "It was not possible to create a closed curve, these are the "
36986  << "vertices of the already sorted polylines\n\n";
36987  unsigned cpolyline = 0;
36988  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
36989  sorted_curve_sections_pt.begin();
36990  it_list != sorted_curve_sections_pt.end();
36991  it_list++)
36992  {
36993  error_message << "Polyline (" << cpolyline << ")\n";
36994  TriangleMeshPolyLine *tmp_poly_pt =
36995  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
36996  const unsigned nvertex = tmp_poly_pt->nvertex();
36997  for (unsigned v = 0; v < nvertex; v++)
36998  {
36999  error_message <<"("<<tmp_poly_pt->vertex_coordinate(v)[0]
37000  <<", "<<tmp_poly_pt->vertex_coordinate(v)[1]<<")\n";
37001  }
37002  error_message << "\n";
37003  cpolyline++;
37004  }
37005  throw OomphLibError(error_message.str(),
37006  OOMPH_CURRENT_FUNCTION,
37007  OOMPH_EXCEPTION_LOCATION);
37008  }
37009 #endif
37010 
37011  // Create a vector version to create the polygon from the sorted
37012  // polyines
37013  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37014  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37015  sorted_curve_sections_pt.begin();
37016  it_list != sorted_curve_sections_pt.end();
37017  it_list++)
37018  {tmp_sorted_curve_sections_pt.push_back((*it_list));}
37019 
37020  // Create a new polygon by using the new created polylines
37021  TriangleMeshPolygon *polygon_pt =
37022  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37023 
37024  // Keep track of new created polygons that need to be deleted!!!
37025  this->Free_polygon_pt.insert(polygon_pt);
37026 
37027  // Store the polygon in the polygons storages
37028  polygons_pt.push_back(polygon_pt);
37029 
37030  npolygons++;
37031 
37032  } // while(nsorted_polylines < nboundary)
37033 
37034  // ------------------------------------------------------------------
37035  // Before filling the data structures we need to identify the outer
37036  // closed boundary and the inner closed boundaries.
37037  // If the nodes are not in order we throw a warning message
37038 
37039  // Index for the polygon that is currently considered as the outer
37040  // boundary
37041  unsigned index_outer = 0;
37042 
37043  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37044  {
37045  // Get the vertices of the outer boundary
37046  Vector<Vector<double> > outer_vertex_coordinates;
37047 
37048  // Flag to know if ALL the inner closed boundaries are inside the
37049  // outer closed boundary
37050  bool all_inner_inside = true;
37051 
37052  // Number of polylines of the outer boundary
37053  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37054  for (unsigned p = 0; p < nouter_polylines; p++)
37055  {
37056  TriangleMeshPolyLine* tmp_poly_pt =
37057  polygons_pt[idx_outer]->polyline_pt(p);
37058  const unsigned nvertex = tmp_poly_pt->nvertex();
37059  for (unsigned v = 0; v < nvertex; v++)
37060  {
37061  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37062  outer_vertex_coordinates.push_back(current_vertex);
37063  } // for (v < nvertex)
37064  } // for (p < nouter_polylines)
37065 
37066  // Now get the vertices for the inner boundaries
37067 
37068  // First get the number of inner closed boundaries (polygons size
37069  // minus one because one of the polygons is considered to be the
37070  // outer closed boundary
37071  const unsigned ninner_polygons = polygons_pt.size() - 1;
37072 
37073  // Store the vertices of the inner closed boundaries
37074  Vector<Vector<Vector<double> > > inner_vertex_coordinates(ninner_polygons);
37075  // Get all the vertices of the inner closed boundaries
37076  for (unsigned i = 0; i <= ninner_polygons; i++)
37077  {
37078  if (i != idx_outer)
37079  {
37080  // Number of polylines of the current internal closed boundary
37081  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37082  for (unsigned p = 0; p < ninner_polylines; p++)
37083  {
37084  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37085  const unsigned nvertex = tmp_poly_pt->nvertex();
37086  for (unsigned v = 0; v < nvertex; v++)
37087  {
37088  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37089  if (i < idx_outer)
37090  {
37091  inner_vertex_coordinates[i].push_back(current_vertex);
37092  }
37093  else if (i > idx_outer)
37094  {
37095  inner_vertex_coordinates[i-1].push_back(current_vertex);
37096  }
37097  } // for (v < nvertex)
37098 
37099  } // for (p < ninner_polylines)
37100 
37101  } // if (i != index_outer)
37102 
37103  } // for (i <= ninner_polygons)
37104 
37105  // Now check that ALL the vertices of ALL the internal closed
37106  // boundaries are inside the outer closed boundary
37107  for (unsigned i = 0; i < ninner_polygons; i++)
37108  {
37109  // Get the number of vertices in the current internal closed
37110  // boundary
37111  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37112  for (unsigned v = 0; v < nvertex_internal; v++)
37113  {
37114  // Get a vertex in the current internal closed boundary
37115  Vector<double> current_point = inner_vertex_coordinates[i][v];
37116  all_inner_inside &=
37117  this->is_point_inside_polygon_helper(outer_vertex_coordinates,
37118  current_point);
37119 
37120  // Check if we should continue checking for more points inside
37121  // the current proposed outer boundary
37122  if (!all_inner_inside)
37123  {
37124  // Break the "for" for the vertices
37125  break;
37126  }
37127 
37128  } // for (v < nvertex_internal)
37129 
37130  // Check if we should continue checking for more inner closed
37131  // boundaries inside the current proposed outer boundary
37132  if (!all_inner_inside)
37133  {
37134  // Break the "for" for the inner boundaries
37135  break;
37136  }
37137 
37138  } // for (i < ninner_polygons)
37139 
37140  // Check if all the vertices of all the polygones are inside the
37141  // current proposed outer boundary
37142  if (all_inner_inside)
37143  {
37144  index_outer = idx_outer;
37145  break;
37146  }
37147 
37148  } // for (idx_outer < npolygons)
37149 
37150 #ifdef PARANOID
37151  // Check if the first nodes listed in the polyfiles correspond to
37152  // the outer boundary, if that is not the case then throw a warning
37153  // message
37154  if (index_outer != 0)
37155  {
37156  std::ostringstream warning_message;
37157  warning_message
37158  << "The first set of nodes listed in the input polyfiles does not\n"
37159  << "correspond to the outer closed boundary. This may lead to\n"
37160  << "problems at the adaptation stage if the holes coordinates\n"
37161  << "are no correctly associated to the inner closed boundaries.\n"
37162  << "You can check the generated mesh by calling the output() method\n"
37163  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37164  OomphLibWarning(warning_message.str(),
37165  OOMPH_CURRENT_FUNCTION,
37166  OOMPH_EXCEPTION_LOCATION);
37167  } // if (index_outer != 0)
37168 #endif
37169 
37170  // ------------------------------------------------------------------
37171  // Now fill the data structures
37172 
37173  // Store outer polygon
37174  // We are assuming there is only one outer polygon
37175  this->Outer_boundary_pt.resize(1);
37176  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37177 
37178  this->Internal_polygon_pt.resize(npolygons-1);
37179  for (unsigned i = 0; i < npolygons; i++)
37180  {
37181  if (i != index_outer)
37182  {
37183  if (i < index_outer)
37184  {
37185  // Store internal polygons by copy constructor
37186  this->Internal_polygon_pt[i] = polygons_pt[i];
37187  }
37188  else if (i > index_outer)
37189  {
37190  // Store internal polygons by copy constructor
37191  this->Internal_polygon_pt[i-1] = polygons_pt[i];
37192  }
37193  } // if (i != index_outer)
37194  } // for (i < npolygons)
37195 
37196  // Before assigning the hole vertex coordinate to the inner closed
37197  // boundaries check that the holes are listed in orderm if that is
37198  // not the case the associate each hole vertex coordinate to the
37199  // inner closed boundaries
37200 
37201  // Store the vertices of the inner closed boundaries
37202  Vector<Vector<Vector<double> > > inner_vertex_coordinates(npolygons-1);
37203  // Get all the vertices of the inner closed boundaries
37204  for (unsigned i = 0; i < npolygons-1; i++)
37205  {
37206  // Number of polylines of the current internal closed boundary
37207  const unsigned ninner_polylines =
37208  this->Internal_polygon_pt[i]->npolyline();
37209  for (unsigned p = 0; p < ninner_polylines; p++)
37210  {
37211  TriangleMeshPolyLine* tmp_poly_pt =
37212  this->Internal_polygon_pt[i]->polyline_pt(p);
37213  // Number of vertices of the current polyline in the current
37214  // internal closed polygon
37215  const unsigned nvertex = tmp_poly_pt->nvertex();
37216  for (unsigned v = 0; v < nvertex; v++)
37217  {
37218  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37219  inner_vertex_coordinates[i].push_back(current_vertex);
37220  } // for (v < nvertex)
37221 
37222  } // for (p < ninner_polylines)
37223 
37224  } // for (i <= ninner_polygons)
37225 
37226  // Holes information
37227  unsigned nholes;
37228  poly_file >> nholes;
37229 
37230 #ifdef PARANOID
37231  if (npolygons > 1 && (npolygons - 1) != nholes)
37232  {
37233  std::ostringstream error_message;
37234  error_message
37235  << "The number of holes (" << nholes << ") does not correspond "
37236  << "with the number\nof internal polygons ("
37237  << npolygons - 1 <<")\n\n"
37238  << "Using polyfiles as input does not currently allows the\n"
37239  << "definition of more than one outer polygon\n\n";
37240  throw OomphLibError(error_message.str(),
37241  OOMPH_CURRENT_FUNCTION,
37242  OOMPH_EXCEPTION_LOCATION);
37243  }
37244 #endif
37245 
37246  // Storage for the holes
37247  Vector<Vector<double> > hole_coordinates(nholes);
37248 
37249  // Dummy for hole number
37250  unsigned dummy_hole;
37251  // Loop over the holes to get centre coords
37252  for(unsigned ihole=0;ihole<nholes;ihole++)
37253  {
37254  hole_coordinates[ihole].resize(2);
37255  // Read the centre value
37256  poly_file >> dummy_hole;
37257  poly_file >> hole_coordinates[ihole][0];
37258  poly_file >> hole_coordinates[ihole][1];
37259  }
37260 
37261  // Vector that store the index of the hole coordinate that
37262  // correspond to each internal closed polygon
37263  Vector<unsigned> index_hole_of_internal_polygon(npolygons-1);
37264  std::map<unsigned, bool> hole_done;
37265 
37266  // Now associate each hole vertex to a corresponding internal closed
37267  // polygon
37268  for (unsigned i = 0; i < npolygons-1; i++)
37269  {
37270  // Find which hole is associated to each internal closed boundary
37271  for (unsigned h = 0; h < nholes; h++)
37272  {
37273  // If the hole has not been previously associated
37274  if (!hole_done[h])
37275  {
37276  // Get the hole coordinate
37277  Vector<double> current_point = hole_coordinates[h];
37278 
37279  const bool hole_in_polygon =
37280  this->is_point_inside_polygon_helper(inner_vertex_coordinates[i],
37281  current_point);
37282 
37283  // If the hole is inside the polygon
37284  if (hole_in_polygon)
37285  {
37286  // Mark the hole as done
37287  hole_done[h] = true;
37288  // Associate the current hole with the current inner closed
37289  // boundary
37290  index_hole_of_internal_polygon[i] = h;
37291  // Break the search
37292  break;
37293  }
37294 
37295  } // if (!hole_done[h])
37296 
37297  } // for (h < nholes)
37298 
37299  } // for (i < npolygons-1)
37300 
37301 #ifdef PARANOID
37302  if (hole_done.size() != npolygons-1)
37303  {
37304  std::ostringstream error_message;
37305  error_message
37306  << "Not all the holes were associated to an internal closed boundary\n"
37307  << "Only ("<<hole_done.size()<<") holes were assigned for a total of\n"
37308  << "(" << npolygons-1 << ") internal closed boundaries.\n"
37309  << "You can check the generated mesh by calling the output() method\n"
37310  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37311  throw OomphLibError(error_message.str(),
37312  OOMPH_CURRENT_FUNCTION,
37313  OOMPH_EXCEPTION_LOCATION);
37314  } // if (index_hole != ihole)
37315 #endif
37316 
37317  // Assign the holes coordinates to the internal polygons
37318  for (unsigned ihole = 0; ihole < nholes; ihole++)
37319  {
37320  // Get the index hole of the current internal closed polygon
37321  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37322 #ifdef PARANOID
37323  // Check if the hole index is the same as the internal closed
37324  // boundary, it means that the holes were listed in the same order
37325  // as the nodes of the internal closed boundaries
37326  if (index_hole != ihole)
37327  {
37328  std::ostringstream error_message;
37329  error_message
37330  << "The hole vertices coordinates are not listed in the same order\n"
37331  << "as the nodes that define the internal closed boundaries.\n"
37332  << "This may lead to problems in case that the holes coordinates\n"
37333  << "were no properly assigned to the internal closed boundaries.\n"
37334  << "You can check the generated mesh by calling the output() method\n"
37335  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37336  throw OomphLibError(error_message.str(),
37337  OOMPH_CURRENT_FUNCTION,
37338  OOMPH_EXCEPTION_LOCATION);
37339  } // if (index_hole != ihole)
37340 #endif
37341 
37342  // Set the hole coordinate for the internal polygon
37343  this->Internal_polygon_pt[ihole]->internal_point() =
37344  hole_coordinates[index_hole];
37345  }
37346 
37347  // Ignore the first line with structure description
37348  poly_file.ignore(80,'\n');
37349 
37350  // Regions information
37351  unsigned nregions;
37352 
37353  // Extract regions information
37354  // But first check if there are regions or not
37355  std::string regions_info_string;
37356 
37357  // Read line up to termination sign
37358  getline(poly_file, regions_info_string);
37359 
37360  // Check if the read string is a number or a comment wrote by triangle,
37361  // if it is a number then that is the number of regions
37362  if (isdigit(regions_info_string.c_str()[0]))
37363  {
37364  nregions = std::atoi(regions_info_string.c_str());
37365  }
37366  else
37367  {
37368  nregions = 0;
37369  }
37370 
37371  // The regions coordinates
37372  std::map<unsigned, Vector<double> > regions_coordinates;
37373 
37374  // Dummy for regions number
37375  unsigned dummy_region;
37376 
37377  unsigned region_id;
37378 
37379  // Loop over the regions to get their coords
37380  for(unsigned iregion=0;iregion<nregions;iregion++)
37381  {
37382  Vector<double> tmp_region_coordinates(2);
37383  // Read the regions coordinates
37384  poly_file >> dummy_region;
37385  poly_file >> tmp_region_coordinates[0];
37386  poly_file >> tmp_region_coordinates[1];
37387  poly_file >> region_id;
37388  regions_coordinates[region_id].resize(2);
37389  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37390  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37391 
37392  // Ignore the first line with structure description
37393  poly_file.ignore(80,'\n');
37394 
37395  // Verify if not using the default region number (zero)
37396  if (region_id == 0)
37397  {
37398  std::ostringstream error_message;
37399  error_message << "Please use another region id different from zero.\n"
37400  << "It is internally used as the default region number.\n";
37401  throw OomphLibError(error_message.str(),
37402  OOMPH_CURRENT_FUNCTION,
37403  OOMPH_EXCEPTION_LOCATION);
37404  }
37405 
37406  }
37407 
37408  // Store the extra regions coordinates
37409  this->Regions_coordinates = regions_coordinates;
37410 
37411  poly_file.close();
37412 
37413  }
37414 
37415 //======================================================================
37416 /// \short Updates the polygon but using the elements area instead of
37417 /// the default refinement and unrefinement methods
37418 //======================================================================
37419 template <class ELEMENT>
37421 update_polygon_using_elements_area(TriangleMeshPolygon* &polygon_pt,
37422  const Vector<double> &target_area)
37423 {
37424  // Verify that there was a change on the polygon representation
37425  unsigned update_was_performed = false;
37426 
37427  const unsigned nele = this->nelement();
37428 
37429  // - Get the vertices along the boundaries and for each element identify
37430  // its associated target error.
37431  // - Get face mesh representation of each polyline.
37432  // - Get the vertices with the help of face elements.
37433  // - Find the global index in the mesh of the face element and use
37434  // it to get its associated target area
37435 
37436  // Get the face mesh representation
37437  Vector<Mesh*> face_mesh_pt;
37438  get_face_mesh_representation(polygon_pt,face_mesh_pt);
37439 
37440  // Create vertices of the polylines by using the vertices of the
37441  // FaceElements
37442  Vector<double> vertex_coord(3); // zeta,x,y
37443  Vector<double> bound_left(1);
37444  Vector<double> bound_right(1);
37445 
37446  unsigned n_polyline = polygon_pt->npolyline();
37447 
37448  // Go for each polyline
37449  for(unsigned p = 0; p < n_polyline; p++)
37450  {
37451  // Get the MeshAsGeomObject representation just once per polyline,
37452  // this object is only used by the
37453  // refine_boundary_constrained_by_target_area() method. We get it
37454  // here to ensure that all processors (in a distributed context)
37455  // get this representation just once, and because an AllToAll MPI
37456  // communication is used in this calling
37457  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
37458 
37459  // Set of coordinates on the boundary
37460  // Set entries are ordered on first entry in vector which stores
37461  // the boundary coordinate so the vertices come out in order!
37462  std::set<Vector<double> > vertex_nodes;
37463 
37464  // Vector to store the vertices, transfer the sorted vertices from the
37465  // set to this vector, --- including the z-value ---
37466  Vector<Vector<double> > tmp_vector_vertex_node;
37467 
37468  // Vector to store the coordinates of the polylines, same as the
37469  // tmp_vector_vertex_node vector (after adding more nodes) but
37470  // --- without the z-value ---, used to re-generate the polylines
37471  Vector<Vector<double> > vector_vertex_node;
37472 
37473 #ifdef OOMPH_HAS_MPI
37474  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37475  // Set of coordinates that are on the boundary (splitted boundary version)
37476  // The first vector is used to allocate the points for each sub-boundary
37477  // Set entries are ordered on first entry in vector which stores
37478  // the boundary coordinate so the vertices come out in order!
37479  Vector<std::set<Vector<double> > >sub_vertex_nodes;
37480 
37481  // Vector to store the vertices, transfer the sorted vertices from the
37482  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37483  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
37484 
37485  // Vector to store the coordinates of the polylines that will represent
37486  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37487  // but --- without the z-value ---, used to generate the sub-polylines
37488  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
37489  // --------- Stuff to deal with splitted boundaries ----------- End ------
37490 #endif
37491 
37492  //Get the boundary id
37493  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37494 
37495  // Get the chunk number
37496  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37497 
37498  /// Use a vector of vector for vertices and target areas to deal
37499  /// with the cases when the boundaries are split by the
37500  /// distribution process
37501 
37502  // Loop over the face elements (ordered) and add their vertices
37503  const unsigned nface_element = face_mesh_pt[p]->nelement();
37504 
37505  // Store the non halo face elements, the ones from which we will
37506  // get the vertices
37507  Vector<FiniteElement*> non_halo_face_element_pt;
37508 
37509  // Map to store the index of the face element on a boundary
37510  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
37511 
37512  for(unsigned ef=0;ef<nface_element;++ef)
37513  {
37514  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37515 #ifdef OOMPH_HAS_MPI
37516  // Skip the halo elements if working with a distributed mesh
37517  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37518  {continue;}
37519 #endif
37520  // Add the face element to the vector
37521  non_halo_face_element_pt.push_back(ele_face_pt);
37522  face_element_index_on_boundary[ele_face_pt] = ef;
37523  }
37524 
37525  // Get the number of non halo face element
37526  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37527 
37528  // Map to know the already sorted face elements
37529  std::map<FiniteElement*,bool> face_element_done;
37530 
37531  // Number of done face elements
37532  unsigned nsorted_face_elements = 0;
37533 
37534 #ifdef OOMPH_HAS_MPI
37535  // Counter for sub_boundaries
37536  unsigned nsub_boundaries = 0;
37537 #endif // #ifdef OOMPH_HAS_MPI
37538 
37539  // Continue until all the face elements have been sorted
37540  // While to deal with split boundaries cases
37541  while(nsorted_face_elements < nnon_halo_face_element)
37542  {
37543  // Get and initial face element
37544  FiniteElement* ele_face_pt = 0;
37545 #ifdef PARANOID
37546  bool found_initial_face_element = false;
37547 #endif
37548 
37549  unsigned iface = 0;
37550  for (iface = 0; iface < nnon_halo_face_element; iface++)
37551  {
37552  ele_face_pt = non_halo_face_element_pt[iface];
37553  // If not done then take it as initial face element
37554  if (!face_element_done[ele_face_pt])
37555  {
37556 #ifdef PARANOID
37557  found_initial_face_element = true;
37558 #endif
37559  nsorted_face_elements++;
37560  iface++;
37561  break;
37562  }
37563  }
37564 
37565 #ifdef PARANOID
37566  if (!found_initial_face_element)
37567  {
37568  std::ostringstream error_message;
37569  error_message
37570  <<"Could not find an initial face element for the current segment\n";
37571  // << "----- Possible memory leak -----\n";
37572  throw OomphLibError(error_message.str(),
37573  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37574  OOMPH_EXCEPTION_LOCATION);
37575  }
37576 #endif
37577 
37578  // Local set of coordinates that are on the boundary
37579  // Set entries are ordered on first entry in vector which stores
37580  // the boundary coordinate so the vertices come out in order!
37581  std::set<Vector<double> > local_vertex_nodes;
37582 
37583  // Vector to store the vertices, transfer the sorted vertices from the
37584  // set (local) to this vector (local), --- including the z-value ---
37585  Vector<Vector<double> > local_tmp_vector_vertex_node;
37586 
37587  // Vector to store the target areas, uses the same approach as the
37588  // set for the local_vertex_nodes, ordered on first entry
37589  std::set<Vector<double> > sorted_target_areas;
37590 
37591  // Vector to store the target areas, used to transfer the sorted target
37592  // areas from "local_sorted_target_areas" set
37593  Vector<double> tmp_sorted_target_areas;
37594 
37595  // -----------------------------------------------------------------
37596  // Add the vertices of the initial face element to the set of
37597  // local sorted vertices
37598  // -----------------------------------------------------------------
37599  unsigned nnode = ele_face_pt->nnode();
37600  // Add the left-hand node to the set:
37601  // Boundary coordinate
37602  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
37603  vertex_coord[0] = bound_left[0];
37604 
37605  // Actual coordinates
37606  for(unsigned i=0;i<2;i++)
37607  {
37608  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
37609  }
37610  local_vertex_nodes.insert(vertex_coord);
37611 
37612  // Add the right-hand nodes to the set:
37613  // Boundary coordinate
37614  ele_face_pt->node_pt(nnode-1)->
37615  get_coordinates_on_boundary(bound,bound_right);
37616  vertex_coord[0] = bound_right[0];
37617 
37618  // Actual coordinates
37619  for(unsigned i=0;i<2;i++)
37620  {
37621  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
37622  }
37623  local_vertex_nodes.insert(vertex_coord);
37624 
37625  // The initial and final node on the set
37626  Node *first_node_pt = ele_face_pt->node_pt(0);
37627  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
37628 
37629  // Mark the current face element as done
37630  face_element_done[ele_face_pt] = true;
37631 
37632  // -------------------------------------------------------
37633  // Find the global index in the mesh of the face element
37634  // and use it to get its associated target area
37635  // -------------------------------------------------------
37636  // Container to store the zeta value (used as index) and
37637  // the associated target area of the element
37638  Vector<double> zeta_target_area_values(2);
37639 
37640  // Use the minimum zeta value to sort the target areas
37641  // along the boundary
37642  zeta_target_area_values[0] =
37643  std::min(bound_left[0], bound_right[0]);
37644 
37645  // Get the index of the face element on the current boundary
37646  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37647  // Get the "ef"-th element on the boundary
37648  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
37649 
37650 #ifdef PARANOID
37651  bool found_global_element_index = false;
37652 #endif
37653  for (unsigned eg = 0 ; eg < nele; eg++)
37654  {
37655  // Get the "eg-th" element
37656  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
37657 
37658  // Compare with the element on the boundary, if equal then
37659  // store the target area
37660  if (el_pt == el_compare_pt)
37661  {
37662  zeta_target_area_values[1] = target_area[eg];
37663 #ifdef PARANOID
37664  found_global_element_index = true;
37665 #endif
37666  break; // break the for (e < nele) global element
37667  } // if element_pt == element_compare_pt
37668  } // for nele (on complete mesh)
37669 
37670 #ifdef PARANOID
37671  if (!found_global_element_index)
37672  {
37673  std::ostringstream error_message;
37674  error_message
37675  << "The global index for the ("<< ef <<")-th face element "
37676  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37677  throw OomphLibError(error_message.str(),
37678  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37679  OOMPH_EXCEPTION_LOCATION);
37680  }
37681 #endif
37682 
37683  // Add the target areas to the sorted set
37684  sorted_target_areas.insert(zeta_target_area_values);
37685  // ------------------------------------------------------------------
37686 
37687  // Continue iterating if a new face element has been added to the
37688  // list
37689  bool face_element_added = false;
37690 
37691  // While a new face element has been added to the set of sorted
37692  // face elements then re-iterate
37693  do
37694  {
37695  // Start from the next face elements since we have already
37696  // added the previous one as the initial face element (any
37697  // previous face element had to be added on previous
37698  // iterations)
37699  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
37700  {
37701  face_element_added = false;
37702  ele_face_pt = non_halo_face_element_pt[iiface];
37703  if (!face_element_done[ele_face_pt])
37704  {
37705  // Get each individual node to check if they are contiguous
37706  nnode = ele_face_pt->nnode();
37707  Node* left_node_pt = ele_face_pt->node_pt(0);
37708  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
37709 
37710  if (left_node_pt == first_node_pt)
37711  {
37712  first_node_pt = right_node_pt;
37713  face_element_added = true;
37714  }
37715  else if (left_node_pt == last_node_pt)
37716  {
37717  last_node_pt = right_node_pt;
37718  face_element_added = true;
37719  }
37720  else if (right_node_pt == first_node_pt)
37721  {
37722  first_node_pt = left_node_pt;
37723  face_element_added = true;
37724  }
37725  else if (right_node_pt == last_node_pt)
37726  {
37727  last_node_pt = left_node_pt;
37728  face_element_added = true;
37729  }
37730 
37731  if (face_element_added)
37732  {
37733  // Add the left-hand node to the set:
37734  // Boundary coordinate
37735  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
37736  vertex_coord[0] = bound_left[0];
37737 
37738  // Actual coordinates
37739  for(unsigned i=0;i<2;i++)
37740  {
37741  vertex_coord[i+1] = left_node_pt->x(i);
37742  }
37743  local_vertex_nodes.insert(vertex_coord);
37744 
37745  // Add the right-hand nodes to the set:
37746  // Boundary coordinate
37747  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
37748  vertex_coord[0] = bound_right[0];
37749 
37750  // Actual coordinates
37751  for(unsigned i=0;i<2;i++)
37752  {
37753  vertex_coord[i+1] = right_node_pt->x(i);
37754  }
37755  local_vertex_nodes.insert(vertex_coord);
37756 
37757  // Mark as done only if one of its nodes has been
37758  // added to the list
37759  face_element_done[ele_face_pt] = true;
37760  nsorted_face_elements++;
37761 
37762  // -----------------------------------------------------
37763  // Find the global index in the mesh of the face element
37764  // and use it to get its associated target area
37765  // -----------------------------------------------------
37766  // Use the minimum zeta value to sort the target areas
37767  // along the boundary
37768  zeta_target_area_values[0] =
37769  std::min(bound_left[0], bound_right[0]);
37770 
37771  // Get the "ef"-th element on the boundary
37772  ef = face_element_index_on_boundary[ele_face_pt];
37773  FiniteElement *lel_pt = this->boundary_element_pt(bound, ef);
37774 
37775 #ifdef PARANOID
37776  found_global_element_index = false;
37777 #endif
37778  for (unsigned eg = 0 ; eg < nele; eg++)
37779  {
37780  // Get the "eg-th" element
37781  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
37782 
37783  // Compare with the element on the boundary, if equal then
37784  // store the target area
37785  if (lel_pt == lel_compare_pt)
37786  {
37787  zeta_target_area_values[1] = target_area[eg];
37788 #ifdef PARANOID
37789  found_global_element_index = true;
37790 #endif
37791  break; // break the for (e < nele) global element
37792  } // if element_pt == element_compare_pt
37793  } // for nele (on complete mesh)
37794 
37795 #ifdef PARANOID
37796  if (!found_global_element_index)
37797  {
37798  std::ostringstream error_message;
37799  error_message
37800  << "The global index for the ("<< ef <<")-th face element "
37801  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37802  throw OomphLibError(error_message.str(),
37803  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37804  OOMPH_EXCEPTION_LOCATION);
37805  }
37806 #endif
37807 
37808  // Add the target areas to the sorted set
37809  sorted_target_areas.insert(zeta_target_area_values);
37810 
37811  break;
37812  }
37813 
37814  } // if (!edge_done[edge])
37815  } // for (iiedge < nedges)
37816  }while(face_element_added &&
37817  (nsorted_face_elements < nnon_halo_face_element));
37818 
37819  // -----------------------------------------------------------------
37820  // At this point we already have a sorted set of nodes and
37821  // can be used to peform the unrefinement and refinement procedures
37822  // -----------------------------------------------------------------
37823 
37824  // Get the number of nodes on the list
37825  const unsigned nlocal_nodes = local_vertex_nodes.size();
37826  // Change representation to vector for easy of handling ...
37827  local_tmp_vector_vertex_node.resize(nlocal_nodes);
37828 
37829  // Copy the vertices of the nodes
37830  unsigned counter = 0;
37831  std::set<Vector<double> >::iterator it_vertex;
37832  for (it_vertex = local_vertex_nodes.begin();
37833  it_vertex != local_vertex_nodes.end();
37834  it_vertex++)
37835  {
37836  local_tmp_vector_vertex_node[counter].resize(3);
37837  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
37838  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
37839  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
37840  counter++;
37841  }
37842 
37843  // ... same for the info. related with the target areas (turn
37844  // into vector)
37845  const unsigned ntarget_areas = sorted_target_areas.size();
37846  tmp_sorted_target_areas.resize(ntarget_areas);
37847  counter = 0;
37848  std::set<Vector<double> >::iterator it_area;
37849  for(it_area = sorted_target_areas.begin();
37850  it_area != sorted_target_areas.end();
37851  ++it_area)
37852  {
37853  tmp_sorted_target_areas[counter] = (*it_area)[1];
37854  ++counter;
37855  }
37856 
37857 #ifdef PARANOID
37858  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
37859  {
37860  std::ostringstream error_message;
37861  error_message
37862  << "The boundary (" << bound << ") was split during the "
37863  << "distribution process.\n"
37864  << "The problem is in the association of the target areas with the\n"
37865  << "elements that gave rise to the vertex coordinates.\n"
37866  << "The number of local nodes (" << nlocal_nodes
37867  << "), on the 'sub-polyline', is not\n"
37868  << "according with the number of target "
37869  << "areas ("<< ntarget_areas << ")\nfor that number of nodes.\n"
37870  << "The target areas number MUST be equal to the number of\n"
37871  << "local nodes minus one\n\n";
37872  throw OomphLibError(error_message.str(),
37873  OOMPH_CURRENT_FUNCTION,
37874  OOMPH_EXCEPTION_LOCATION);
37875  }
37876 #endif
37877 
37878  // -------------------------------------------------------------------
37879  // Update the vertices along the boundary using the target area
37880  // to define the distance among them
37881  // -------------------------------------------------------------------
37882 
37883  // Tolerance below which the middle point can be deleted
37884  // (ratio of deflection to element length)
37885  double unrefinement_tolerance=
37886  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
37887 
37888  // Apply unrefinement
37889  bool unrefinement_applied =
37890  unrefine_boundary_constrained_by_target_area(
37891  bound, chunk, local_tmp_vector_vertex_node,
37892  unrefinement_tolerance, tmp_sorted_target_areas);
37893 
37894  // Tolerance for refinement
37895  double refinement_tolerance=
37896  polygon_pt->polyline_pt(p)->refinement_tolerance();
37897 
37898  // Apply refinement
37899  bool refinement_applied =
37900  refine_boundary_constrained_by_target_area(
37901  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
37902  refinement_tolerance, tmp_sorted_target_areas);
37903 
37904  // Clear the local containter to recover the nodes ordered using the
37905  // zeta value
37906  local_vertex_nodes.clear();
37907 
37908  // At the end of each unrefinement/refinement step store the new nodes
37909  // on the set that will give rise to the vertices of the new polyline
37910  // representation
37911  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
37912  for (unsigned i = 0; i < nnew_nodes; i++)
37913  {
37914  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
37915  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
37916  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
37917  vertex_nodes.insert(vertex_coord); // Global container
37918  local_vertex_nodes.insert(vertex_coord);
37919  }
37920 
37921  // Update the flag to indicate whether an unrefinement or
37922  // refinement was applied
37923  update_was_performed = (unrefinement_applied || refinement_applied);
37924 
37925 #ifdef OOMPH_HAS_MPI
37926  if (this->is_mesh_distributed())
37927  {
37928  // Add the set of vertices for the boundary, this will help to
37929  // detect if we need to deal with sub-boundaries
37930  sub_vertex_nodes.push_back(local_vertex_nodes);
37931  // Increase the counter for sub-boundaries
37932  nsub_boundaries++;
37933  }
37934 #endif
37935 
37936  } // while(nsorted_face_elements < nnon_halo_face_element)
37937 
37938  // Now turn into vector for ease of handling...
37939  unsigned npoly_vertex = vertex_nodes.size();
37940  // This will store all the vertices whether the boundary was split
37941  // or not
37942  tmp_vector_vertex_node.resize(npoly_vertex);
37943  unsigned count = 0;
37944  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
37945  it!=vertex_nodes.end(); ++it)
37946  {
37947  tmp_vector_vertex_node[count].resize(3);
37948  tmp_vector_vertex_node[count][0] = (*it)[0];
37949  tmp_vector_vertex_node[count][1] = (*it)[1];
37950  tmp_vector_vertex_node[count][2] = (*it)[2];
37951  ++count;
37952  }
37953 
37954 #ifdef OOMPH_HAS_MPI
37955  // --------- Stuff for the sub_boundaries ----- Begin section ---------
37956 #ifdef PARANOID
37957  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
37958  if (nsub_boundaries_set != nsub_boundaries)
37959  {
37960  std::ostringstream error_message;
37961  error_message
37962  << "The number of found sub-boundaries and the number of counted\n"
37963  << "sub-boundaries are different:\n"
37964  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
37965  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
37966  throw OomphLibError(error_message.str(),
37967  OOMPH_CURRENT_FUNCTION,
37968  OOMPH_EXCEPTION_LOCATION);
37969  }
37970 #endif
37971 
37972  // Are there sub-boundaries (only appear in distributed meshes)
37973  if (this->is_mesh_distributed() && nsub_boundaries > 1)
37974  {
37975  // Mark the boundary as been splitted in the partition process
37976  this->Boundary_was_splitted[bound] = true;
37977  // Resize the vector to store the info. of sub-boundaries
37978  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
37979  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
37980  {
37981  // Turn info. into vector for ease of handling...
37982  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
37983  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
37984  unsigned subcount = 0;
37985  std::set<Vector<double> >::iterator subit;
37986  for(subit = sub_vertex_nodes[isub].begin();
37987  subit != sub_vertex_nodes[isub].end(); ++subit)
37988  {
37989  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
37990  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
37991  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
37992  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
37993  ++subcount;
37994  }
37995  }
37996  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
37997  // --------- Stuff for the sub_boundaries ----- End section ------------
37998 #endif // OOMPH_HAS_MPI
37999 
38000  // For further processing the three-dimensional vector has to be
38001  // reduced to a two-dimensional vector
38002  unsigned n_vertex=tmp_vector_vertex_node.size();
38003 
38004  // Resize the vector for vectices
38005  vector_vertex_node.resize(n_vertex);
38006  for(unsigned i=0;i<n_vertex;i++)
38007  {
38008  vector_vertex_node[i].resize(2);
38009  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
38010  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
38011  }
38012 
38013 #ifdef OOMPH_HAS_MPI
38014  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38015  // Verify if need to deal with sub_boundaries
38016  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38017  {
38018  // For further processing the three-dimensional vector
38019  // has to be reduced to a two-dimensional vector
38020  // Resize the vector to store the info. of sub-boundaries
38021  sub_vector_vertex_node.resize(nsub_boundaries);
38022  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38023  {
38024  const unsigned subn_vertex =
38025  sub_tmp_vector_vertex_node[isub].size();
38026  // Resize the vector for vectices
38027  sub_vector_vertex_node[isub].resize(subn_vertex);
38028  for(unsigned i=0;i<subn_vertex;i++)
38029  {
38030  sub_vector_vertex_node[isub][i].resize(2);
38031  sub_vector_vertex_node[isub][i][0]=
38032  sub_tmp_vector_vertex_node[isub][i][1];
38033  sub_vector_vertex_node[isub][i][1]=
38034  sub_tmp_vector_vertex_node[isub][i][2];
38035  }
38036  }
38037  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38038 
38039  // We already have the info. for the sub-boundaries (if necessary)
38040  // and then we can create the sub-boundaries representations to
38041  // ease the generation of the mesh by Triangle
38042 
38043  // --------- Stuff for the sub_boundaries ----- End section ------------
38044  #endif // OOMPH_HAS_MPI
38045 
38046  // --------------------------------------------------------------------
38047  // Check for contiguousness
38048  // --------------------------------------------------------------------
38049 #ifdef OOMPH_HAS_MPI
38050  // Only perform this checking if the mesh is not distributed. When
38051  // the mesh is distributed the polylines continuity is addressed
38052  // by the sort_polylines_helper() method
38053  if (!this->is_mesh_distributed())
38054 #endif
38055  {
38056  if ( p > 0 )
38057  {
38058  //Final end point of previous line
38059  Vector<double> final_vertex_of_previous_segment;
38060  unsigned n_prev_vertex =
38061  polygon_pt->curve_section_pt(p-1)->nvertex();
38062  final_vertex_of_previous_segment =
38063  polygon_pt->polyline_pt(p-1)->
38064  vertex_coordinate(n_prev_vertex-1);
38065 
38066  unsigned prev_seg_boundary_id =
38067  polygon_pt->curve_section_pt(p-1)->boundary_id();
38068 
38069  //Find the error between the final vertex of the previous
38070  //line and the first vertex of the current line
38071  double error = 0.0;
38072  for(unsigned i=0;i<2;i++)
38073  {
38074  const double dist =
38075  final_vertex_of_previous_segment[i] -
38076  (*vector_vertex_node.begin())[i];
38077  error += dist*dist;
38078  }
38079  error = sqrt(error);
38080 
38081  //If the error is bigger than the tolerance then
38082  //we probably need to reverse, but better check
38083  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38084  {
38085  //Find the error between the final vertex of the previous
38086  //line and the last vertex of the current line
38087  double rev_error = 0.0;
38088  for(unsigned i=0;i<2;i++)
38089  {
38090  const double dist =
38091  final_vertex_of_previous_segment[i] -
38092  (*--vector_vertex_node.end())[i];
38093  rev_error += dist*dist;
38094  }
38095  rev_error = sqrt(rev_error);
38096 
38097  if(rev_error >
38098  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38099  {
38100  // It could be possible that the first segment be reversed
38101  // and we did not notice it because this check does not
38102  // apply for the first segment. We can verify if the first
38103  // segment is reversed by using the vertex number 1
38104  if (p == 1)
38105  {
38106  //Initial end point of previous line
38107  Vector<double> initial_vertex_of_previous_segment;
38108 
38109  initial_vertex_of_previous_segment =
38110  polygon_pt->polyline_pt(p-1)->
38111  vertex_coordinate(0);
38112 
38113  unsigned prev_seg_boundary_id =
38114  polygon_pt->curve_section_pt(p-1)->boundary_id();
38115 
38116  //Find the error between the initial vertex of the previous
38117  //line and the first vertex of the current line
38118  double error = 0.0;
38119  for(unsigned i=0;i<2;i++)
38120  {
38121  const double dist =
38122  initial_vertex_of_previous_segment[i] -
38123  (*vector_vertex_node.begin())[i];
38124  error += dist*dist;
38125  }
38126  error = sqrt(error); // Reversed only the previous one
38127 
38128  //If the error is bigger than the tolerance then
38129  //we probably need to reverse, but better check
38130  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38131  {
38132  //Find the error between the final vertex of the previous
38133  //line and the last vertex of the current line
38134  double rev_error = 0.0;
38135  for(unsigned i=0;i<2;i++)
38136  {
38137  const double dist =
38138  initial_vertex_of_previous_segment[i] -
38139  (*--vector_vertex_node.end())[i];
38140  rev_error += dist*dist;
38141  }
38142  rev_error = sqrt(rev_error); // Reversed both the current one and
38143  // the previous one
38144 
38145  if (rev_error >
38146  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38147  {
38148  std::ostringstream error_stream;
38149  error_stream
38150  <<"The distance between the first node of the current\n"
38151  <<"line segment (boundary "<<bound<<") and either end of "
38152  << "the previous line segment\n"
38153  << "(boundary "<<prev_seg_boundary_id<<") is bigger than "
38154  << "the desired tolerance "
38155  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38156  << ".\n"
38157  << "This suggests that the polylines defining the "
38158  << "polygonal\n"
38159  << "representation are not properly ordered.\n"
38160  << "Fail on last vertex of polyline: ("
38161  << prev_seg_boundary_id << ") and\n"
38162  << "first vertex of polyline (" << bound << ").\n"
38163  << "This should have failed when first trying to "
38164  << "construct the\npolygon.\n";
38165  throw OomphLibError(error_stream.str(),
38166  OOMPH_CURRENT_FUNCTION,
38167  OOMPH_EXCEPTION_LOCATION);
38168  }
38169  else
38170  {
38171  // Reverse both
38172  // Reverse the current vector to line up with the
38173  // previous one
38174  std::reverse(vector_vertex_node.begin(),
38175  vector_vertex_node.end());
38176 
38177  polygon_pt->polyline_pt(p-1)->reverse();
38178  }
38179  }
38180  else
38181  {
38182  // Reverse the previous one
38183  polygon_pt->polyline_pt(p-1)->reverse();
38184  }
38185 
38186  } // if p == 1
38187  else
38188  {
38189  std::ostringstream error_stream;
38190  error_stream
38191  <<"The distance between the first node of the current\n"
38192  <<"line segment (boundary " << bound << ") and either end of "
38193  <<"the previous line segment\n"
38194  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
38195  <<"desired tolerance " <<
38196  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
38197  <<"This suggests that the polylines defining the polygonal\n"
38198  <<"representation are not properly ordered.\n"
38199  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
38200  << ") and\nfirst vertex of polyline ("<<bound << ").\n"
38201  << "This should have failed when first trying to construct"
38202  << " the polygon.\n";
38203  throw OomphLibError(error_stream.str(),
38204  OOMPH_CURRENT_FUNCTION,
38205  OOMPH_EXCEPTION_LOCATION);
38206  }
38207  }
38208  else
38209  {
38210  //Reverse the current vector to line up with the previous one
38211  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
38212  }
38213  } // error
38214 
38215  } // if ( p > 0 )
38216 
38217  } // if (!this->is_mesh_distributed())
38218 
38219  // --------------------------------------------------------------------
38220  // Update the polylines representation
38221  // --------------------------------------------------------------------
38222 
38223  // Always update the polylines representation, in a distributed
38224  // mesh it is necessary to update the polyline representation since
38225  // it may no longer have vertices (the boundary may not be part of
38226  // the domain in the current processor)
38227 
38228  // The new nunber of vertices
38229  n_vertex = vector_vertex_node.size();
38230 
38231  // Now update the polyline according to the new vertices
38232  TriangleMeshPolyLine *tmp_polyline_pt =
38233  new TriangleMeshPolyLine(vector_vertex_node,bound);
38234 
38235  // Create a temporal "curve section" version of the recently
38236  // created polyline
38237  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
38238 
38239  // Tolerance below which the middle point can be deleted (ratio of
38240  // deflection to element length)
38241  double unrefinement_tolerance=
38242  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38243 
38244  // Tolerance to add points
38245  double refinement_tolerance=
38246  polygon_pt->polyline_pt(p)->refinement_tolerance();
38247 
38248  // Establish refinement and unrefinement tolerance
38249  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38250  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38251 
38252  // Establish the maximum length constraint
38253  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38254  tmp_polyline_pt->set_maximum_length(maximum_length);
38255 
38256 #ifdef OOMPH_HAS_MPI
38257  // If the mesh is distributed check that the polyline still has
38258  // vertices
38259  if (this->is_mesh_distributed())
38260  {
38261  if (n_vertex >= 2)
38262  {
38263  // Pass the connection information from the old polyline to the
38264  // new one
38265  this->copy_connection_information(polygon_pt->polyline_pt(p),
38266  tmp_curve_section_pt);
38267  } // if (n_vertex >= 2)
38268  } // if (this->is_mesh_distributed())
38269  else
38270 #endif
38271  {
38272  // Pass the connection information from the old polyline to the
38273  // new one
38274  this->copy_connection_information(polygon_pt->polyline_pt(p),
38275  tmp_curve_section_pt);
38276  }
38277 
38278  // Now update the polyline according to the new vertices but first
38279  // check if the object is allowed to delete the representation or
38280  // if it should be done by other object
38281  bool delete_it_on_destructor = false;
38282 
38283  std::set<TriangleMeshCurveSection*>::iterator it =
38284  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38285 
38286  if (it!=this->Free_curve_section_pt.end())
38287  {
38288  this->Free_curve_section_pt.erase(it);
38289  delete polygon_pt->curve_section_pt(p);
38290  delete_it_on_destructor = true;
38291  }
38292 
38293  // -------------------------------------------------------
38294  // Copying the new representation
38295  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38296 
38297  // Update the Boundary - Polyline map
38298  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38299 
38300  if (delete_it_on_destructor)
38301  {
38302  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38303  }
38304 
38305 #ifdef OOMPH_HAS_MPI
38306  // --------- Stuff for the sub_boundaries ----- Begin section --------
38307  // Verify if need to deal with sub_boundaries
38308  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38309  {
38310  // Create temporary representations for the boundaries, only to
38311  // create the mesh when calling Triangle
38312 
38313  // Clear all previous stored data
38314  this->Boundary_subpolylines[bound].clear();
38315 
38316  // Create storage for the sub-boundaries
38317  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38318  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38319  {
38320  // Update the polyline according to the sub set of vertices,
38321  TriangleMeshPolyLine *sub_tmp_polyline_pt =
38322  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38323 
38324  // Add the sub-polyline to the container to represent the
38325  // boundary in parts
38326  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38327 
38328  // No need to send the unrefinement/refinement and maximum
38329  // length constraints since these are only temporary
38330  // representations. These polylines can be deleted once the new
38331  // polygons that represent the distributed domain have been
38332  // created
38333 
38334  } // for (isub < nsub_boundaries)
38335 
38336  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38337  // --------- Stuff for the sub_boundaries ----- End section ---------
38338  #endif // OOMPH_HAS_MPI
38339 
38340  // Delete the allocated memory for the geometric object that
38341  // represents the boundary
38342  delete mesh_geom_obj_pt;
38343 
38344  } // for (p < n_polyline)
38345 
38346  // Cleanup the face mesh
38347  for(unsigned p=0;p<n_polyline;p++)
38348  {
38349  face_mesh_pt[p]->flush_node_storage();
38350  delete face_mesh_pt[p];
38351  }
38352 
38353  return update_was_performed;
38354 
38355 }
38356 
38357 //======================================================================
38358 /// \short Updates the open curve but using the elements area instead
38359 /// of the default refinement and unrefinement methods
38360 //======================================================================
38361 template <class ELEMENT>
38363 update_open_curve_using_elements_area(TriangleMeshOpenCurve* &open_curve_pt,
38364  const Vector<double> &target_area)
38365 {
38366  // Verify if there was a change on the open curve representation
38367  unsigned update_was_performed = false;
38368 
38369  const unsigned nele = this->nelement();
38370 
38371  // - Get the vertices along the boundaries and for each element identify
38372  // its associated target error.
38373  // - Get face mesh representation of each polyline.
38374  // - Get the vertices with the help of face elements.
38375  // - Find the global index in the mesh of the face element
38376  // and use it to get its associated target area.
38377 
38378  // Get the face mesh representation
38379  Vector<Mesh*> face_mesh_pt;
38380  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
38381 
38382  // Create vertices of the polylines by using the vertices of the
38383  // FaceElements
38384  Vector<double> vertex_coord(3); // zeta,x,y
38385  Vector<double> bound_left(1);
38386  Vector<double> bound_right(1);
38387 
38388  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38389 
38390  // Go for each curve section
38391  for(unsigned cs = 0; cs < ncurve_section; cs++)
38392  {
38393  // Get the MeshAsGeomObject representation just once per polyline,
38394  // this object is only used by the
38395  // refine_boundary_constrained_by_target_area() method. We get it
38396  // here to ensure that all processors (in a distributed context)
38397  // get this representation just once, and because an AllToAll MPI
38398  // communication is used in this calling
38399  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
38400 
38401  //Get the boundary id
38402  const unsigned bound =
38403  open_curve_pt->curve_section_pt(cs)->boundary_id();
38404 
38405  // Get the chunk number
38406  const unsigned chunk =
38407  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38408 
38409  /// Use a vector of vector for vertices and target areas to deal
38410  /// with the cases when the boundaries are split by the
38411  /// distribution process. Internal boundaries may be completely or
38412  /// partially overlapped by shared boundaries
38413 
38414  // Loop over the face elements and add their vertices (they are
38415  // automatically sorted because of the set)
38416  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38417 
38418  // Store the non halo elements and the element at the other side of
38419  // the boundary (whatever it be halo or not), the first will be the
38420  // ones from which we will get the vertices (in even position)
38421  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38422 
38423  // Map to store the index of the face element on a boundary
38424  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
38425 
38426  // Map to know the already sorted face elements
38427  std::map<FiniteElement*,bool> face_element_done;
38428 
38429  for(unsigned ef = 0; ef < nface_element; ++ef)
38430  {
38431  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38432 
38433  // Skip the halo elements (not used as base elements, only
38434  // include those elements whose element at the other side of the
38435  // boundary is non halo)
38436 #ifdef OOMPH_HAS_MPI
38437  if (this->is_mesh_distributed())
38438  {
38439  // Only work with non-halo elements
38440  if (ele_face_pt->is_halo()) {continue;}
38441  }
38442 #endif
38443 
38444  // Check if not already done
38445  if (!face_element_done[ele_face_pt])
38446  {
38447  // Add the element and look for the element at the other side
38448  // of the boundary to add it immediately after the new added
38449  // element
38450  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38451  // Create the map of the face element with the index
38452  face_element_index_on_boundary[ele_face_pt] = ef;
38453  // Mark the current element as done
38454  face_element_done[ele_face_pt] = true;
38455  // Get the number of nodes
38456  const unsigned nnodes = ele_face_pt->nnode();
38457  // Get the left and right node to look for the elements at the
38458  // other side of the boundary
38459  Node* left_node_pt = ele_face_pt->node_pt(0);
38460  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
38461 #ifdef PARANOID
38462  // Flag to know if the element at the other side of the
38463  // boundary was found
38464  bool found_other_side_face_ele = false;
38465 #endif
38466  for (unsigned iface = 0; iface < nface_element; iface++)
38467  {
38468  // Get the candidate face element
38469  FiniteElement *cele_face_pt =
38470  face_mesh_pt[cs]->finite_element_pt(iface);
38471  // Check if not already done
38472  if (!face_element_done[cele_face_pt])
38473  {
38474  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38475  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
38476  // Check if the nodes are the same
38477  if ((left_node_pt == cleft_node_pt &&
38478  right_node_pt == cright_node_pt) ||
38479  (left_node_pt == cright_node_pt &&
38480  right_node_pt == cleft_node_pt))
38481  {
38482  // Add the element to the storage
38483  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38484  // ... and mark the element as done
38485  face_element_done[cele_face_pt] = true;
38486  // Create the map of the face element with the index
38487  face_element_index_on_boundary[cele_face_pt] = iface;
38488 #ifdef PARANOID
38489  // Set the flag of found other side face element
38490  found_other_side_face_ele = true;
38491 #endif
38492  break;
38493  }
38494  }
38495  } // (iface < nface_element)
38496 
38497 #ifdef PARANOID
38498  if (!found_other_side_face_ele)
38499  {
38500  std::ostringstream error_message;
38501  error_message
38502  << "The face element at the other side of the boundary ("
38503  << bound << ") was not found!!\n"
38504  << "These are the nodes of the face element:\n"
38505  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
38506  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
38507  throw OomphLibError(error_message.str(),
38508  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38509  OOMPH_EXCEPTION_LOCATION);
38510  }
38511 #endif
38512  } // if (!face_ele_done[ele_face_pt])
38513 
38514  } // (ef < nface_element)
38515 
38516  // Clear the map of the already done face elements
38517  // This will be used to help sorting the face elements
38518  face_element_done.clear();
38519 
38520  // Set of coordinates that are on the boundary
38521  // The entries are sorted on first entry in vector which stores
38522  // the boundary coordinate so the vertices come out in order!
38523  std::set<Vector<double> > vertex_nodes;
38524 
38525  // Vector to store the vertices, transfer the sorted vertices from the
38526  // set to this vector, --- including the z-value ---
38527  Vector<Vector<double> > tmp_vector_vertex_node;
38528 
38529  // Vector to store the coordinates of the polylines, same as the
38530  // tmp_vector_vertex_node vector (after adding more nodes) but
38531  // --- without the z-value ---, used to re-generate the polylines
38532  Vector<Vector<double> > vector_vertex_node;
38533 
38534 #ifdef OOMPH_HAS_MPI
38535  // Indicates if the set of vertices give rise to a internal
38536  // boundary that will be used as shared boundary or as normal
38537  // internal boundary -- Only used to deal with internal boundaries
38538  // in a distributed scheme
38539  std::vector<bool> internal_to_shared_boundary;
38540 
38541  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38542  // Set of coordinates that are on the boundary (splitted boundary version)
38543  // The first vector is used to allocate the points for each sub-boundary
38544  // Set entries are ordered on first entry in vector which stores
38545  // the boundary coordinate so the vertices come out in order!
38546  Vector<std::set<Vector<double> > > sub_vertex_nodes;
38547 
38548  // Vector to store the vertices, transfer the sorted vertices from the
38549  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38550  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
38551 
38552  // Vector to store the coordinates of the polylines that will represent
38553  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38554  // but --- without the z-value ---, used to generate the sub-polylines
38555  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
38556 
38557  // --------- Stuff to deal with splitted boundaries ----------- End ------
38558 
38559 #endif // #ifdef OOMPH_HAS_MPI
38560 
38561  // Sort the face element, those that have both elements (one at
38562  // each side of the boundary) marked as nonhalo, and those with one
38563  // nonhalo an the other as halo
38564 
38565  // Number of done face elements
38566  unsigned nsorted_face_elements = 0;
38567 
38568 #ifdef OOMPH_HAS_MPI
38569  // Counter for sub_boundaries
38570  unsigned nsub_boundaries = 0;
38571 #endif // #ifdef OOMPH_HAS_MPI
38572 
38573  // Total number of non halo double face element
38574  const unsigned nnon_halo_doubled_face_ele =
38575  non_halo_doubled_face_element_pt.size();
38576 
38577  // Continue until all the face elements have been sorted
38578  // This while is to deal with the cases of splitted boundaries
38579  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
38580  {
38581  // Get and initial face element
38582  FiniteElement* ele_face_pt = 0;
38583  FiniteElement* repeated_ele_face_pt = 0;
38584 #ifdef PARANOID
38585  bool found_initial_face_element = false;
38586 #endif
38587 
38588  // Flag to know if we are working with a face element which the
38589  // face element at the other side of the boundary is also non
38590  // halo
38591  bool both_root_face_elements_are_nonhalo = false;
38592 
38593  unsigned iface = 0;
38594  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
38595  {
38596  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38597  // If not done then take it as initial face element
38598  if (!face_element_done[ele_face_pt])
38599  {
38600  // Mark it as done
38601  face_element_done[ele_face_pt] = true;
38602  // Get the other side boundary face element
38603  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
38604  // ... also mark as done the repeated face element
38605  face_element_done[repeated_ele_face_pt] = true;
38606 
38607 #ifdef OOMPH_HAS_MPI
38608  if (!repeated_ele_face_pt->is_halo())
38609  {both_root_face_elements_are_nonhalo = true;}
38610 #endif // #ifdef OOMPH_HAS_MPI
38611 
38612  // Plus two because internal boundaries have
38613  // two face elements per each edge
38614  nsorted_face_elements+=2;
38615  iface+=2;
38616 #ifdef PARANOID
38617  // And set the flag to true
38618  found_initial_face_element = true;
38619 #endif
38620  break;
38621  }
38622  }
38623 
38624 #ifdef PARANOID
38625  if (!found_initial_face_element)
38626  {
38627  std::ostringstream error_message;
38628  error_message
38629  <<"Could not find an initial face element for the current segment\n";
38630  throw OomphLibError(error_message.str(),
38631  OOMPH_CURRENT_FUNCTION,
38632  OOMPH_EXCEPTION_LOCATION);
38633  }
38634 #endif
38635 
38636  // Local set of coordinates that are on the boundary Set entries
38637  // are ordered on first entry in vector which stores the boundary
38638  // coordinate so the vertices come out in order
38639  std::set<Vector<double> > local_vertex_nodes;
38640 
38641  // Vector to store the vertices, transfer the sorted vertices from the
38642  // set (local) to this vector (local), --- including the z-value ---
38643  Vector<Vector<double> > local_tmp_vector_vertex_node;
38644 
38645  // Vector to store the target areas, uses the same approach as the
38646  // set for the local_vertex_nodes, ordered on first entry
38647  std::set<Vector<double> > sorted_target_areas;
38648 
38649  // Vector to store the target areas, used to transfer the sorted target
38650  // areas from "sorted_target_areas" set
38651  Vector<double> tmp_sorted_target_areas;
38652 
38653  // ------------------------------------------------------------------
38654  // Add the vertices of the initial face element to the set of local
38655  // sorted vertices
38656  // ------------------------------------------------------------------
38657  const unsigned nnode = ele_face_pt->nnode();
38658  // Add the left-hand node to the set:
38659  // Boundary coordinate
38660  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
38661  vertex_coord[0] = bound_left[0];
38662 
38663  // Actual coordinates
38664  for(unsigned i=0;i<2;i++)
38665  {
38666  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
38667  }
38668  local_vertex_nodes.insert(vertex_coord);
38669 
38670  // Add the right-hand node to the set:
38671  // Boundary coordinate
38672  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
38673  bound_right);
38674  vertex_coord[0] = bound_right[0];
38675 
38676  // Actual coordinates
38677  for(unsigned i=0;i<2;i++)
38678  {
38679  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
38680  }
38681  local_vertex_nodes.insert(vertex_coord);
38682 
38683  // The initial and final node on the set
38684  Node *first_node_pt = ele_face_pt->node_pt(0);
38685  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
38686 
38687  // -----------------------------------------------------
38688  // Find the global index in the mesh of the face element
38689  // and use it to get its associated target area
38690  // -----------------------------------------------------
38691  // Container to store the zeta value (used as index) and
38692  // the associated target area of the element
38693  Vector<double> zeta_target_area_values(2);
38694 
38695  // Use the minimum zeta value to sort the target areas
38696  // along the boundary
38697  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38698 
38699  // Get the index of the face element on the current boundary
38700  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38701  // Get the "ef"-th element on the boundary
38702  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
38703  double target_area_face_element = 0.0;
38704 
38705 #ifdef PARANOID
38706  bool found_global_element_index = false;
38707 #endif
38708  for (unsigned eg = 0 ; eg < nele; eg++)
38709  {
38710  // Get the "eg-th" element
38711  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38712 
38713  // Compare with the element on the boundary, if equal then
38714  // store the target area
38715  if (el_pt == el_compare_pt)
38716  {
38717  target_area_face_element = target_area[eg];
38718 #ifdef PARANOID
38719  found_global_element_index = true;
38720 #endif
38721  break; // break the for (eg < nele) global element
38722  } // if el_pt == el_compare_pt
38723  } // for nele (on complete mesh)
38724 
38725 #ifdef PARANOID
38726  if (!found_global_element_index)
38727  {
38728  std::ostringstream error_message;
38729  error_message
38730  << "The global index for the ("<< ef <<")-th face element "
38731  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38732  throw OomphLibError(error_message.str(),
38733  OOMPH_CURRENT_FUNCTION,
38734  OOMPH_EXCEPTION_LOCATION);
38735  }
38736 #endif
38737 
38738  // Get the index of the repeated face element on the current boundary
38739  const unsigned ref = face_element_index_on_boundary[repeated_ele_face_pt];
38740  FiniteElement *rel_pt = this->boundary_element_pt(bound, ref);
38741  double target_area_repeated_face_element = 0.0;
38742 
38743 #ifdef PARANOID
38744  bool found_global_repeated_element_index = false;
38745 #endif
38746  for (unsigned eg = 0 ; eg < nele; eg++)
38747  {
38748  // Get the "eg-th" element
38749  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38750 
38751  // Compare with the element on the boundary, if equal then
38752  // store the target area
38753  if (rel_pt == el_compare_pt)
38754  {
38755  target_area_repeated_face_element = target_area[eg];
38756 #ifdef PARANOID
38757  found_global_repeated_element_index = true;
38758 #endif
38759  break; // break the for (eg < nele) global element
38760  } // if rel_pt == el_compare_pt
38761  } // for nele (on complete mesh)
38762 
38763 #ifdef PARANOID
38764  if (!found_global_repeated_element_index)
38765  {
38766  std::ostringstream error_message;
38767  error_message
38768  << "The global index for the ("<< ref <<")-th face element "
38769  << "on\nthe ("<< bound <<")-th boundary was not found (repeated "
38770  << "face element)!!!";
38771  throw OomphLibError(error_message.str(),
38772  OOMPH_CURRENT_FUNCTION,
38773  OOMPH_EXCEPTION_LOCATION);
38774  }
38775 #endif
38776 
38777  // Choose the minimum target area from both elements, one at each side
38778  // of the edge on the boundary
38779  zeta_target_area_values[1]=std::min(target_area_face_element,
38780  target_area_repeated_face_element);
38781 
38782  // Add the target areas to the sorted set
38783  sorted_target_areas.insert(zeta_target_area_values);
38784  // ------------------------------------------------------------------
38785 
38786  // Continue iterating if a new face element has been added to the
38787  // list
38788  bool face_element_added = false;
38789 
38790  // While a new face element has been added to the set of sorted
38791  // face elements then re-iterate
38792  do
38793  {
38794  // Start from the next face elements since we have already
38795  // added the previous one as the initial face element (any
38796  // previous face element had to be added on previous
38797  // iterations)
38798  for (unsigned iiface=iface;
38799  iiface<nnon_halo_doubled_face_ele;iiface+=2)
38800  {
38801  face_element_added = false;
38802  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
38803 
38804  // Check that the face element with which we are working has
38805  // the same conditions as the root face element (both faces
38806  // are nonhalo or one face is halo and the other nonhalo)
38807 
38808  // Get the face element at the other side of the boundary
38809  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38810  bool both_face_elements_are_nonhalo = false;
38811 
38812 #ifdef OOMPH_HAS_MPI
38813  if (!repeated_ele_face_pt->is_halo())
38814  {both_face_elements_are_nonhalo = true;}
38815 #endif // #ifdef OOMPH_HAS_MPI
38816 
38817  if (!face_element_done[ele_face_pt] &&
38818  (both_face_elements_are_nonhalo ==
38819  both_root_face_elements_are_nonhalo))
38820  {
38821  // Get each individual node to check if they are contiguous
38822  const unsigned nlnode = ele_face_pt->nnode();
38823  Node* left_node_pt = ele_face_pt->node_pt(0);
38824  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
38825 
38826  if (left_node_pt == first_node_pt)
38827  {
38828  first_node_pt = right_node_pt;
38829  face_element_added = true;
38830  }
38831  else if (left_node_pt == last_node_pt)
38832  {
38833  last_node_pt = right_node_pt;
38834  face_element_added = true;
38835  }
38836  else if (right_node_pt == first_node_pt)
38837  {
38838  first_node_pt = left_node_pt;
38839  face_element_added = true;
38840  }
38841  else if (right_node_pt == last_node_pt)
38842  {
38843  last_node_pt = left_node_pt;
38844  face_element_added = true;
38845  }
38846 
38847  if (face_element_added)
38848  {
38849  // Add the left-hand node to the set:
38850  // Boundary coordinate
38851  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
38852  vertex_coord[0] = bound_left[0];
38853 
38854  // Actual coordinates
38855  for(unsigned i=0;i<2;i++)
38856  {
38857  vertex_coord[i+1] = left_node_pt->x(i);
38858  }
38859  local_vertex_nodes.insert(vertex_coord);
38860 
38861  // Add the right-hand nodes to the set:
38862  // Boundary coordinate
38863  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
38864  vertex_coord[0] = bound_right[0];
38865 
38866  // Actual coordinates
38867  for(unsigned i=0;i<2;i++)
38868  {
38869  vertex_coord[i+1] = right_node_pt->x(i);
38870  }
38871  local_vertex_nodes.insert(vertex_coord);
38872 
38873  // Mark as done only if one of its nodes has been
38874  // added to the list
38875  face_element_done[ele_face_pt] = true;
38876  // .. also mark as done the face element at the othe side of
38877  // the boundary
38878  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38879  face_element_done[repeated_ele_face_pt] = true;
38880  // ... and increase the number of sorted face elements
38881  nsorted_face_elements+=2;
38882 
38883  // -----------------------------------------------------
38884  // Find the global index in the mesh of the face element
38885  // and use it to get its associated target area
38886  // -----------------------------------------------------
38887  // Use the minimum zeta value to sort the target areas
38888  // along the boundary
38889  zeta_target_area_values[0] =
38890  std::min(bound_left[0], bound_right[0]);
38891 
38892  // Get the "ef"-th element on the boundary
38893  const unsigned lef = face_element_index_on_boundary[ele_face_pt];
38894  FiniteElement *lel_pt = this->boundary_element_pt(bound, lef);
38895 
38896 #ifdef PARANOID
38897  found_global_element_index = false;
38898 #endif
38899  for (unsigned eg = 0 ; eg < nele; eg++)
38900  {
38901  // Get the "eg-th" element
38902  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38903 
38904  // Compare with the element on the boundary, if equal then
38905  // store the target area
38906  if (lel_pt == lel_compare_pt)
38907  {
38908  target_area_face_element = target_area[eg];
38909 #ifdef PARANOID
38910  found_global_element_index = true;
38911 #endif
38912  break; // break the for (eg < nele) global element
38913  } // if lel_pt == lel_compare_pt
38914  } // for nele (on complete mesh)
38915 
38916 #ifdef PARANOID
38917  if (!found_global_element_index)
38918  {
38919  std::ostringstream error_message;
38920  error_message
38921  << "The global index for the ("<< lef <<")-th face element "
38922  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38923  throw OomphLibError(error_message.str(),
38924  OOMPH_CURRENT_FUNCTION,
38925  OOMPH_EXCEPTION_LOCATION);
38926  }
38927 #endif
38928 
38929  // Get the index of the repeated face element on the boundary
38930  const unsigned rlef =
38931  face_element_index_on_boundary[repeated_ele_face_pt];
38932  FiniteElement *rlel_pt = this->boundary_element_pt(bound, rlef);
38933 
38934 #ifdef PARANOID
38935  found_global_repeated_element_index = false;
38936 #endif
38937  for (unsigned eg = 0 ; eg < nele; eg++)
38938  {
38939  // Get the "eg-th" element
38940  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38941 
38942  // Compare with the element on the boundary, if equal then
38943  // store the target area
38944  if (rlel_pt == lel_compare_pt)
38945  {
38946  target_area_repeated_face_element = target_area[eg];
38947 #ifdef PARANOID
38948  found_global_repeated_element_index = true;
38949 #endif
38950  break; // break the for (eg < nele) global element
38951  } // if rlel_pt == el_compare_pt
38952  } // for nele (on complete mesh)
38953 
38954 #ifdef PARANOID
38955  if (!found_global_repeated_element_index)
38956  {
38957  std::ostringstream error_message;
38958  error_message
38959  << "The global index for the ("<< rlef <<")-th face element "
38960  << "on\nthe ("<< bound <<")-th boundary was not found "
38961  << "(repeated face element)!!!";
38962  throw OomphLibError(error_message.str(),
38963  OOMPH_CURRENT_FUNCTION,
38964  OOMPH_EXCEPTION_LOCATION);
38965  }
38966 #endif
38967 
38968  // Choose the minimum target area from both elements, one
38969  // at each side of the edge on the boundary
38970  zeta_target_area_values[1] =
38971  std::min(target_area_face_element,
38972  target_area_repeated_face_element);
38973 
38974  // Add the target areas to the sorted set
38975  sorted_target_areas.insert(zeta_target_area_values);
38976 
38977  break;
38978  }
38979 
38980  } // if (!face_element_done[[ele_face_pt])
38981  } // for (iiface<nnon_halo_doubled_face_ele)
38982  }while(face_element_added &&
38983  (nsorted_face_elements < nnon_halo_doubled_face_ele));
38984 
38985  // -------------------------------------------------------------
38986  // At this point we already have a sorted set of nodes and can
38987  // be used to peform the unrefinement and refinement procedures
38988  // -------------------------------------------------------------
38989 
38990  // Get the number of nodes on the list
38991  const unsigned nlocal_nodes = local_vertex_nodes.size();
38992  // Change representation to vector for easy of handling ...
38993  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38994 
38995  // Copy the vertices of the nodes
38996  unsigned counter = 0;
38997  std::set<Vector<double> >::iterator it_vertex;
38998  for (it_vertex = local_vertex_nodes.begin();
38999  it_vertex != local_vertex_nodes.end();
39000  it_vertex++)
39001  {
39002  local_tmp_vector_vertex_node[counter].resize(3);
39003  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39004  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39005  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39006  counter++;
39007  }
39008 
39009  // ... same for the info. related with the target areas (turn
39010  // into vector)
39011  const unsigned ntarget_areas = sorted_target_areas.size();
39012  tmp_sorted_target_areas.resize(ntarget_areas);
39013  counter = 0;
39014  std::set<Vector<double> >::iterator it_area;
39015  for(it_area = sorted_target_areas.begin();
39016  it_area != sorted_target_areas.end();
39017  ++it_area)
39018  {
39019  tmp_sorted_target_areas[counter] = (*it_area)[1];
39020  ++counter;
39021  }
39022 
39023 #ifdef PARANOID
39024  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
39025  {
39026  std::ostringstream error_message;
39027  error_message
39028  << "The boundary (" << bound << ") was split during the "
39029  << "distribution process.\n"
39030  << "The problem comes when associating the target areas with the "
39031  << "elements that gave\nrise to the vertex coordinates.\n"
39032  << "The number of local nodes on the 'sub-polyline' ("
39033  << nlocal_nodes << ") is not according with the number of target\n"
39034  << "areas ("<< ntarget_areas << ") for that number of nodes.\n"
39035  << "The target areas number must be equal to the number of nodes-1\n";
39036  throw OomphLibError(error_message.str(),
39037  OOMPH_CURRENT_FUNCTION,
39038  OOMPH_EXCEPTION_LOCATION);
39039  }
39040 #endif
39041 
39042  // The unrefinement and refinement process needs to be applied
39043  // from the bottom-left node since the internal open curve could
39044  // lie on the shared boundaries
39045  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
39046  local_tmp_vector_vertex_node[0][2])
39047  {
39048  std::reverse(local_tmp_vector_vertex_node.begin(),
39049  local_tmp_vector_vertex_node.end());
39050  std::reverse(tmp_sorted_target_areas.begin(),
39051  tmp_sorted_target_areas.end());
39052  }
39053  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
39054  local_tmp_vector_vertex_node[0][2])
39055  {
39056  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
39057  local_tmp_vector_vertex_node[0][1])
39058  {
39059  std::reverse(local_tmp_vector_vertex_node.begin(),
39060  local_tmp_vector_vertex_node.end());
39061  std::reverse(tmp_sorted_target_areas.begin(),
39062  tmp_sorted_target_areas.end());
39063  }
39064  }
39065 
39066  // ------------------------------------------------------------
39067  // Create the vertices along the boundary using the target
39068  // area to define the distance among them
39069  // ------------------------------------------------------------
39070 
39071  // Tolerance below which the middle point can be deleted
39072  // (ratio of deflection to element length)
39073  double unrefinement_tolerance=
39074  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39075 
39076  // Apply unrefinement
39077  bool unrefinement_applied =
39078  unrefine_boundary_constrained_by_target_area(
39079  bound, chunk, local_tmp_vector_vertex_node,
39080  unrefinement_tolerance, tmp_sorted_target_areas);
39081 
39082  // Tolerance for refinement
39083  double refinement_tolerance=
39084  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39085 
39086  // Apply refinement
39087  bool refinement_applied =
39088  refine_boundary_constrained_by_target_area(
39089  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
39090  refinement_tolerance, tmp_sorted_target_areas);
39091 
39092  // Clear the local containter to recover the nodes ordered using
39093  // the zeta value
39094  local_vertex_nodes.clear();
39095 
39096  // At the end of each unrefinement/refinement step store the new
39097  // nodes on the set that will give rise to the vertices of the
39098  // new polyline representation
39099  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39100  for (unsigned i = 0; i < nnew_nodes; i++)
39101  {
39102  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39103  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39104  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39105  vertex_nodes.insert(vertex_coord); // Global container
39106  local_vertex_nodes.insert(vertex_coord);
39107  }
39108 
39109  // Update the flag to indicate whether an unrefinement or
39110  // refinement was applied
39111  update_was_performed = (unrefinement_applied || refinement_applied);
39112 
39113 #ifdef OOMPH_HAS_MPI
39114  if (this->is_mesh_distributed())
39115  {
39116  // Add the set of vertices for the boundary, this will help to
39117  // detect if we need to deal with sub_boundaries and
39118  // sub_polylines representations
39119  sub_vertex_nodes.push_back(local_vertex_nodes);
39120  // Increase the counter for sub_boundaries
39121  nsub_boundaries++;
39122 
39123  // Mark if the polyline created by these vertices will be used
39124  // as a shared boundary or as an internal boundary
39125  if (both_root_face_elements_are_nonhalo)
39126  {internal_to_shared_boundary.push_back(false);}
39127  else
39128  {internal_to_shared_boundary.push_back(true);}
39129  }
39130 #endif
39131 
39132  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39133  // This while is in charge of sorting all the face elements to
39134  // create the new representation of the polyline (also deals
39135  // with the sub-boundary cases)
39136 
39137  // Now turn into vector for ease of handling...
39138  const unsigned npoly_vertex = vertex_nodes.size();
39139  tmp_vector_vertex_node.resize(npoly_vertex);
39140  unsigned count = 0;
39141  for (std::set<Vector<double> >::iterator it = vertex_nodes.begin();
39142  it!=vertex_nodes.end(); ++it)
39143  {
39144  tmp_vector_vertex_node[count].resize(3);
39145  tmp_vector_vertex_node[count][0] = (*it)[0];
39146  tmp_vector_vertex_node[count][1] = (*it)[1];
39147  tmp_vector_vertex_node[count][2] = (*it)[2];
39148  ++count;
39149  }
39150 
39151 #ifdef OOMPH_HAS_MPI
39152  // Check that the number of set of vertices marked to be part of a
39153  // shared boundary or of an internal boundaries be the same as the
39154  // total number of sub-boundaries
39155 #ifdef PARANOID
39156  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39157  const unsigned ninternal_to_shared_boundaries =
39158  internal_to_shared_boundary.size();
39159  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39160  {
39161  std::ostringstream error_message;
39162  error_message
39163  << "The number of found sub-boundaries and the number of marked "
39164  << "internal\nboundaries are different\n"
39165  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39166  << "Number of marked internal boundaries: ("
39167  << ninternal_to_shared_boundaries << ")\n\n";
39168  throw OomphLibError(error_message.str(),
39169  OOMPH_CURRENT_FUNCTION,
39170  OOMPH_EXCEPTION_LOCATION);
39171  }
39172 #endif
39173 
39174  // --------- Stuff for the sub_boundaries ----- Begin section -------
39175 #ifdef PARANOID
39176  if (nsub_boundaries_set != nsub_boundaries)
39177  {
39178  std::ostringstream error_message;
39179  error_message
39180  << "The number of found sub-boundaries and the number of counted\n"
39181  << "sub-boundaries are different:\n"
39182  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39183  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
39184  throw OomphLibError(error_message.str(),
39185  OOMPH_CURRENT_FUNCTION,
39186  OOMPH_EXCEPTION_LOCATION);
39187  }
39188 #endif
39189 
39190  // Verify if need to deal with sub_boundaries
39191  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39192  {
39193  // Mark the boundary as been splitted in the partition process
39194  this->Boundary_was_splitted[bound] = true;
39195 
39196  // Resize the vector to store the info. of sub-boundaries
39197  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39198  // Loop over the sub-boundaries
39199  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39200  {
39201  // Turn info. into vector for ease of handling...
39202  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39203  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39204  unsigned subcount = 0;
39205  std::set<Vector<double> >::iterator subit;
39206  for(subit = sub_vertex_nodes[isub].begin();
39207  subit != sub_vertex_nodes[isub].end(); ++subit)
39208  {
39209  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39210  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39211  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39212  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39213  ++subcount;
39214  }
39215  }
39216  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39217  // --------- Stuff for the sub_boundaries ----- End section ----------
39218 #endif // OOMPH_HAS_MPI
39219 
39220  // For further processing the three-dimensional vector has to be
39221  // reduced to a two-dimensional vector
39222  unsigned n_vertex=tmp_vector_vertex_node.size();
39223 
39224  // Resize the vector for vectices
39225  vector_vertex_node.resize(n_vertex);
39226  for(unsigned i=0;i<n_vertex;i++)
39227  {
39228  vector_vertex_node[i].resize(2);
39229  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
39230  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
39231  }
39232 
39233 #ifdef OOMPH_HAS_MPI
39234  // --------- Stuff for the sub_boundaries ----- Begin section -------
39235  // Verify if need to deal with sub_boundaries
39236  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39237  {
39238  // For further processing the three-dimensional vector has to be
39239  // reduced to a two-dimensional vector
39240  // Resize the vector to store the info. of sub-boundaries
39241  sub_vector_vertex_node.resize(nsub_boundaries);
39242  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39243  {
39244  const unsigned subn_vertex =
39245  sub_tmp_vector_vertex_node[isub].size();
39246  // Resize the vector for vectices
39247  sub_vector_vertex_node[isub].resize(subn_vertex);
39248  for(unsigned i=0;i<subn_vertex;i++)
39249  {
39250  sub_vector_vertex_node[isub][i].resize(2);
39251  sub_vector_vertex_node[isub][i][0]=
39252  sub_tmp_vector_vertex_node[isub][i][1];
39253  sub_vector_vertex_node[isub][i][1]=
39254  sub_tmp_vector_vertex_node[isub][i][2];
39255  }
39256  }
39257  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39258 
39259  // We already have the info. for the sub-boundaries (if necessary)
39260  // and then we can create the sub-boundaries representations to
39261  // ease the generation of the mesh by Triangle
39262 
39263  // --------- Stuff for the sub_boundaries ----- End section ---------
39264 #endif // OOMPH_HAS_MPI
39265 
39266  // ------------------------------------------------------------------
39267  // Check for contiguousness
39268  // ------------------------------------------------------------------
39269 #ifdef OOMPH_HAS_MPI
39270  // Only perform this checking if the mesh is not distributed When
39271  // the mesh is distributed the polylines continuity is addressed by
39272  // the sort_polylines_helper() method
39273  if (!this->is_mesh_distributed())
39274 #endif
39275  {
39276  if ( cs > 0 )
39277  {
39278  //Final end point of previous line
39279  Vector<double> final_vertex_of_previous_segment;
39280  unsigned n_prev_vertex =
39281  open_curve_pt->curve_section_pt(cs-1)->nvertex();
39282  final_vertex_of_previous_segment =
39283  open_curve_pt->polyline_pt(cs-1)->
39284  vertex_coordinate(n_prev_vertex-1);
39285 
39286  unsigned prev_seg_boundary_id =
39287  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39288 
39289  //Find the error between the final vertex of the previous
39290  //line and the first vertex of the current line
39291  double error = 0.0;
39292  for(unsigned i=0;i<2;i++)
39293  {
39294  const double dist =
39295  final_vertex_of_previous_segment[i] -
39296  (*vector_vertex_node.begin())[i];
39297  error += dist*dist;
39298  }
39299  error = sqrt(error);
39300 
39301  //If the error is bigger than the tolerance then
39302  //we probably need to reverse, but better check
39303  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39304  {
39305  //Find the error between the final vertex of the previous
39306  //line and the last vertex of the current line
39307  double rev_error = 0.0;
39308  for(unsigned i=0;i<2;i++)
39309  {
39310  const double dist =
39311  final_vertex_of_previous_segment[i] -
39312  (*--vector_vertex_node.end())[i];
39313  rev_error += dist*dist;
39314  }
39315  rev_error = sqrt(rev_error);
39316 
39317  if(rev_error >
39318  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39319  {
39320  // It could be possible that the first segment be reversed and we
39321  // did not notice it because this check does not apply for the
39322  // first segment. We can verify if the first segment is reversed
39323  // by using the vertex number 1
39324  if (cs == 1)
39325  {
39326  //Initial end point of previous line
39327  Vector<double> initial_vertex_of_previous_segment;
39328 
39329  initial_vertex_of_previous_segment =
39330  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
39331 
39332  unsigned prev_seg_boundary_id =
39333  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39334 
39335  //Find the error between the initial vertex of the previous
39336  //line and the first vertex of the current line
39337  double error = 0.0;
39338  for(unsigned i=0;i<2;i++)
39339  {
39340  const double dist =
39341  initial_vertex_of_previous_segment[i] -
39342  (*vector_vertex_node.begin())[i];
39343  error += dist*dist;
39344  }
39345  error = sqrt(error); // Reversed only the previous one
39346 
39347  //If the error is bigger than the tolerance then
39348  //we probably need to reverse, but better check
39349  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39350  {
39351  //Find the error between the final vertex of the previous
39352  //line and the last vertex of the current line
39353  double rev_error = 0.0;
39354  for(unsigned i=0;i<2;i++)
39355  {
39356  const double dist =
39357  initial_vertex_of_previous_segment[i] -
39358  (*--vector_vertex_node.end())[i];
39359  rev_error += dist*dist;
39360  }
39361  rev_error = sqrt(rev_error); // Reversed both the current
39362  // one and the previous one
39363 
39364  if (rev_error >
39365  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39366  {
39367  std::ostringstream error_stream;
39368  error_stream
39369  <<"The distance between the first node of the current\n"
39370  <<"line segment (boundary "<<bound<<") and either end of "
39371  <<"the previous line segment\n"
39372  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
39373  << " the desired tolerance " <<
39374  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
39375  <<"This suggests that the polylines defining the polygonal\n"
39376  <<"representation are not properly ordered.\n"
39377  <<"Fail on last vertex of polyline: ("
39378  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
39379  <<bound<< ").\nThis should have failed when first trying to "
39380  <<"construct the\npolygon.\n";
39381  throw OomphLibError(error_stream.str(),
39382  OOMPH_CURRENT_FUNCTION,
39383  OOMPH_EXCEPTION_LOCATION);
39384  }
39385  else
39386  {
39387  // Reverse both
39388  // Reverse the current vector to line up with the previous one
39389  std::reverse(vector_vertex_node.begin(),
39390  vector_vertex_node.end());
39391  open_curve_pt->polyline_pt(cs-1)->reverse();
39392  }
39393  }
39394  else
39395  {
39396  // Reverse the previous one
39397  open_curve_pt->polyline_pt(cs-1)->reverse();
39398  }
39399 
39400  } // if (cs == 1)
39401  else
39402  {
39403  std::ostringstream error_stream;
39404  error_stream
39405  <<"The distance between the first node of the current\n"
39406  <<"line segment (boundary " << bound << ") and either end of "
39407  <<"the previous line segment\n"
39408  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
39409  <<"desired tolerance " <<
39410  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
39411  <<"This suggests that the polylines defining the polygonal\n"
39412  <<"representation are not properly ordered.\n"
39413  <<"Fail on last vertex of polyline: ("<<prev_seg_boundary_id
39414  <<") and\nfirst vertex of polyline (" <<bound << ").\n"
39415  <<"This should have failed when first trying to construct\n"
39416  << "the polygon.\n";
39417  throw OomphLibError(error_stream.str(),
39418  OOMPH_CURRENT_FUNCTION,
39419  OOMPH_EXCEPTION_LOCATION);
39420  }
39421  }
39422  else
39423  {
39424  //Reverse the current vector to line up with the previous one
39425  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
39426  }
39427 
39428  }
39429 
39430  } // if (cs > 0)
39431 
39432  } // if (!this->is_mesh_distributed())
39433 
39434  // ---------------------------------------------------------------
39435  // Update the polylines representation
39436  // ---------------------------------------------------------------
39437  // Always update the polylines representation, in a distributed
39438  // mesh it is necessary to update the polyline representation since
39439  // it may no longer have vertices (the boundary may not be part of
39440  // the domain in the current processor)
39441 
39442  // The new number of vertices
39443  n_vertex = vector_vertex_node.size();
39444 
39445  // Update the polyline according to the new vertices
39446  TriangleMeshPolyLine *tmp_polyline_pt =
39447  new TriangleMeshPolyLine(vector_vertex_node,bound);
39448 
39449  // Create a temporal "curve section" version of the recently
39450  // created polyline
39451  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
39452 
39453  // Tolerance below which the middle point can be deleted (ratio of
39454  // deflection to element length)
39455  double unrefinement_tolerance=
39456  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39457 
39458  // Tolerance to add points
39459  double refinement_tolerance=
39460  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39461 
39462  // Establish refinement and unrefinement tolerance
39463  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39464  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39465 
39466  // Establish the maximum length constraint
39467  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39468  tmp_polyline_pt->set_maximum_length(maximum_length);
39469 
39470 #ifdef OOMPH_HAS_MPI
39471  // If the mesh is distributed check that the polyline still has
39472  // vertices
39473  if (this->is_mesh_distributed())
39474  {
39475  if (n_vertex >= 2)
39476  {
39477  // Pass the connection information from the old polyline to
39478  // the new one
39479  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39480  tmp_curve_section_pt);
39481  } // if (n_vertex >= 2)
39482  } // if (this->is_mesh_distributed())
39483  else
39484 #endif
39485  {
39486  // Pass the connection information from the old polyline to the
39487  // new one
39488  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39489  tmp_curve_section_pt);
39490  }
39491 
39492  // Now update the polyline according to the new vertices but first
39493  // check if the object is allowed to delete the representation or
39494  // if it should be done by other object
39495  bool delete_it_on_destructor = false;
39496 
39497  std::set<TriangleMeshCurveSection*>::iterator it =
39498  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39499 
39500  if (it!=this->Free_curve_section_pt.end())
39501  {
39502  this->Free_curve_section_pt.erase(it);
39503  delete open_curve_pt->curve_section_pt(cs);
39504  delete_it_on_destructor = true;
39505  }
39506 
39507  // -------------------------------------------------------------
39508  // Copying the new representation
39509  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39510 
39511  // Update the Boundary - Polyline map
39512  this->Boundary_curve_section_pt[bound] =
39513  open_curve_pt->curve_section_pt(cs);
39514 
39515  if (delete_it_on_destructor)
39516  {
39517  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39518  }
39519 
39520 #ifdef OOMPH_HAS_MPI
39521  // If there are not sub-boundaries mark the boundary if need to be
39522  // trated as shared or as internal boundary
39523  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39524  {
39525  // Clear all previous stored data
39526  this->Boundary_marked_as_shared_boundary[bound].clear();
39527 
39528  // .. and store the flag for the boundary
39529  this->Boundary_marked_as_shared_boundary[bound].push_back(
39530  internal_to_shared_boundary[0]);
39531  }
39532  // --------- Stuff for the sub_boundaries ----- Begin section --------
39533  // Verify if need to deal with sub_boundaries
39534  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39535  {
39536  // Create temporary representations for the boundaries, only to
39537  // create the mesh when calling Triangle
39538 
39539  // Clear all previous stored data
39540  this->Boundary_subpolylines[bound].clear();
39541  // Now create storage for the sub-boundaries
39542  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39543 
39544  // Clear all previous stored data
39545  this->Boundary_marked_as_shared_boundary[bound].clear();
39546  // Create storage to mark the internal boundaries as shared
39547  // boundaries
39548  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39549  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39550  {
39551  // Now update the polyline according to the sub set of
39552  // vertices, set the chunk number of the polyline
39553  TriangleMeshPolyLine *sub_tmp_polyline_pt =
39554  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39555 
39556  // Add the sub-polyline to the container to represent the
39557  // boundary in parts
39558  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39559 
39560  // Copy the flag that mark the boundary as internal or as
39561  // shared bound
39562  this->Boundary_marked_as_shared_boundary[bound][isub] =
39563  internal_to_shared_boundary[isub];
39564 
39565  // No need to send the unrefinement/refinement and maximum
39566  // length constraints since these are only temporary
39567  // representations
39568 
39569  // But we certanly we need to pass the connection information
39570  // to the sub-polylines
39571  // Get a curve section representation of the sub-polyline
39572  TriangleMeshCurveSection *tmp_sub_curve_section_pt =
39573  sub_tmp_polyline_pt;
39574  this->copy_connection_information_to_sub_polylines(
39575  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39576 
39577  } // for (isub < nsub_boundaries)
39578 
39579  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39580  // --------- Stuff for the sub_boundaries ----- End section ---------
39581 #endif // OOMPH_HAS_MPI
39582 
39583  // Delete the allocated memory for the geometric object
39584  // that represents the curvilinear boundary
39585  delete mesh_geom_obj_pt;
39586 
39587  } // for (cs < ncurve_section)
39588 
39589  // Cleanup the face mesh
39590  for(unsigned p = 0; p < ncurve_section; p++)
39591  {
39592  face_mesh_pt[p]->flush_node_storage();
39593  delete face_mesh_pt[p];
39594  }
39595 
39596  return update_was_performed;
39597 
39598 }
39599 
39600 #ifdef OOMPH_HAS_MPI
39601 //======================================================================
39602 /// \short Updates the polylines using the elements area as
39603 /// constraint for the number of points along the boundaries
39604 //======================================================================
39605 template <class ELEMENT>
39607 update_shared_curve_using_elements_area(Vector<TriangleMeshPolyLine*>
39608  &vector_polyline_pt,
39609  const Vector<double> &target_areas)
39610 {
39611  // Flag to check if there were a change on the shared boundary
39612  // representation
39613  unsigned update_was_performed = false;
39614 
39615  // Go through all the shared boundaries/polylines
39616  const unsigned n_polylines = vector_polyline_pt.size();
39617  for (unsigned pp = 0; pp < n_polylines; pp++)
39618  {
39619  // Get the boundary id of the current polyline
39620  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39621 
39622  // Get the chunk number
39623  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39624 
39625  // Get the face elements that created the shared boundary from the
39626  // bulk shared boundary elements
39627 
39628  // Compute the face elements from the shared boundary elements,
39629  // create an association from the face element with the "bulk"
39630  // elements
39631  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39632 
39633  // The temporary storage for the halo face elements
39634  Vector<FiniteElement*> halo_shared_face_ele_pt;
39635  // The temporary storage for the nonhalo face elements
39636  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39637 
39638  // Get the number of shared boundary elements associated with the
39639  // current shared boundary
39640  const unsigned nshared_bound_ele =
39641  this->nshared_boundary_element(shd_bnd_id);
39642 
39643  // Loop over the elements in the shared boundary to create the face
39644  // elements
39645  for (unsigned e = 0; e < nshared_bound_ele; e++)
39646  {
39647  // Get the shared boundary element
39648  FiniteElement* bulk_ele_pt =
39649  this->shared_boundary_element_pt(shd_bnd_id, e);
39650 
39651  // Get the face index
39652  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39653 
39654  // Before adding the new element we need to ensure that the edge
39655  // that this element represents has not been already added
39656  FiniteElement* face_ele_pt =
39657  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39658 
39659  // Establish the association between the bulk element and the
39660  // face element
39661  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39662 
39663  // Nonhalo element
39664  if (!bulk_ele_pt->is_halo())
39665  {
39666  // Add nonhalo shared face element to the container
39667  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39668  }
39669  else // halo element
39670  {
39671  // Add halo shared face element to the container
39672  halo_shared_face_ele_pt.push_back(face_ele_pt);
39673  }
39674 
39675  } // for (e < nshared_bound_ele)
39676 
39677  // Now we have the face elements, we need to ensure that the halo
39678  // and nonhalo bulk element are sorted one after the other
39679  Vector<Vector<FiniteElement*> > unsorted_shared_bulk_ele_pt;
39680 
39681  // Mark the face elements already used
39682  std::map<FiniteElement*, bool> shared_face_done;
39683 
39684  // Get the number of nonhalo face elements
39685  const unsigned nnonhalo_face_shared_ele =
39686  nonhalo_shared_face_ele_pt.size();
39687 
39688  // Get the number of halo face elements
39689  const unsigned nhalo_face_shared_ele =
39690  halo_shared_face_ele_pt.size();
39691 
39692 #ifdef PARANOID
39693  // The number of nonhalo shared face boundary elements must be the
39694  // half of the total number of shared boundary elements
39695  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39696  {
39697  std::ostringstream error_message;
39698  error_message
39699  << "The number of shared boundary elements (" << nshared_bound_ele
39700  << ") is not the double\nof the number of unsorted NONHALO shared "
39701  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39702  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39703  throw OomphLibError(error_message.str(),
39704  OOMPH_CURRENT_FUNCTION,
39705  OOMPH_EXCEPTION_LOCATION);
39706  }
39707 
39708  // The number of halo shared face boundary elements must be the
39709  // half of the total number of shared boundary elements
39710  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39711  {
39712  std::ostringstream error_message;
39713  error_message
39714  << "The number of shared boundary elements (" << nshared_bound_ele
39715  << ") is not the double\nof the number of unsorted HALO shared "
39716  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
39717  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39718  throw OomphLibError(error_message.str(),
39719  OOMPH_CURRENT_FUNCTION,
39720  OOMPH_EXCEPTION_LOCATION);
39721  }
39722 #endif
39723 
39724  // ------------------------------------------------------------------
39725  // Loop over the nonhalo face elements and look for the halo face
39726  // element at the other side of the shared boundary
39727  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39728  {
39729  // Get the inh-th face element
39730  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
39731 
39732  // Get the number of nodes on the face element
39733  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
39734  // Get the first and last node on the element
39735  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
39736  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
39737 
39738  // Now find the (halo) face element at the other side of the
39739  // shared boundary
39740  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
39741  {
39742  // Get the ih-th face element
39743  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
39744 
39745  // Check that the face element has not been done
39746  if (!shared_face_done[halo_face_ele_pt])
39747  {
39748  // Get the number of nodes on the face element
39749  const unsigned nnodes_h = halo_face_ele_pt->nnode();
39750  // Get the first and last node on the element
39751  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
39752  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
39753 
39754  // If the nodes are the same then we have found the (halo)
39755  // face element at the other side of the shared boundary
39756  if (nh_first_node_pt == h_first_node_pt &&
39757  nh_last_node_pt == h_last_node_pt)
39758  {
39759  // Get the BULK elements associated with the face elements
39760  Vector<FiniteElement*> tmp_bulk_element_pt;
39761  // Get the BULK elements associated to the face elements
39762  // (the nonhalo and the halo)
39763  FiniteElement* nonhalo_bulk_ele_pt =
39764  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39765  FiniteElement* halo_bulk_ele_pt =
39766  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39767 
39768  // Add the BULK elements to the temporal storage
39769  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39770  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39771 
39772  // Store the pair of elements associated to the "edge"
39773  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39774 
39775  // Mark the face elements as done
39776  shared_face_done[nonhalo_face_ele_pt] = true;
39777  shared_face_done[halo_face_ele_pt] = true;
39778 
39779  // Break the loop for (ih < nhalo_face_shared_ele)
39780  break;
39781  } // if (nh_first_node_pt == h_first_node_pt &&
39782  // nh_last_node_pt == h_last_node_pt)
39783  else if (nh_first_node_pt == h_last_node_pt &&
39784  nh_last_node_pt == h_first_node_pt)
39785  {
39786  // Get the BULK elements associated with the face elements
39787  Vector<FiniteElement*> tmp_bulk_element_pt;
39788  // Get the BULK elements associated to the face elements
39789  // (the nonhalo and the halo)
39790  FiniteElement* nonhalo_bulk_ele_pt =
39791  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39792  FiniteElement* halo_bulk_ele_pt =
39793  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39794 
39795  // Add the BULK elements to the temporal storage
39796  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39797  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39798 
39799  // Store the pair of elements associated to the "edge"
39800  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39801 
39802  // Mark the face elements as done
39803  shared_face_done[nonhalo_face_ele_pt] = true;
39804  shared_face_done[halo_face_ele_pt] = true;
39805 
39806  // Break the loop for (ih < nhalo_face_shared_ele)
39807  break;
39808  } // else if (nh_first_node_pt == h_last_node_pt &&
39809  // nh_last_node_pt == h_first_node_pt)
39810 
39811  } // if (face_done[halo_face_ele_pt])
39812 
39813  } // for (ih < nhalo_face_shared_ele)
39814 
39815  } // for (inh < nnonhalo_face_shared_ele)
39816 
39817  // -------------------------------------------------------------
39818  // Now sort the face elements
39819  // -------------------------------------------------------------
39820 
39821  // We already have the shared face elements that make the shared
39822  // boundary (and the bulk elements), now sort them to create a
39823  // contiguous boundary
39824 
39825 #ifdef PARANOID
39826  const unsigned nunsorted_shared_bulk_ele =
39827  unsorted_shared_bulk_ele_pt.size();
39828 
39829  // The number of unsorted shared BULK elements MUST be the same
39830  // as the number of shared_boundary elements divided by two
39831  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
39832  {
39833  std::ostringstream error_message;
39834  error_message
39835  << "The number of shared boundary elements (" << nshared_bound_ele
39836  << ") is not the double\nof the number of unsorted shared bulk "
39837  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
39838  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39839  throw OomphLibError(error_message.str(),
39840  OOMPH_CURRENT_FUNCTION,
39841  OOMPH_EXCEPTION_LOCATION);
39842  }
39843 
39844  // The number of done shared face elements MUST be the same as the
39845  // sum of the nonhalo and halo shared boundary face elements
39846  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
39847  shared_face_done.size())
39848  {
39849  std::ostringstream error_message;
39850  error_message
39851  << "The number of DONE shared boundary face elements ("
39852  << shared_face_done.size() << ") is not the same\n as the sum of"
39853  << "the nonhalo face shared boundary elements ("
39854  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
39855  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
39856  << "current boundary (" << shd_bnd_id << ")\n\n";
39857  throw OomphLibError(error_message.str(),
39858  OOMPH_CURRENT_FUNCTION,
39859  OOMPH_EXCEPTION_LOCATION);
39860  }
39861 #endif
39862 
39863  // Clear the already done face elements
39864  shared_face_done.clear();
39865 
39866  // The number of sorted face elements
39867  unsigned nsorted_face_ele = 0;
39868 
39869  // Storing for the sorting nodes extracted from the face
39870  // elements. This are also used to update the polyline
39871  std::list<Node*> sorted_nodes;
39872 
39873  // Storing for the sorted shared face elements
39874  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
39875 
39876  // Get the root face element
39877  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
39878  nsorted_face_ele++;
39879 
39880  // Mark face as done
39881  shared_face_done[root_face_ele_pt] = true;
39882 
39883  // The initial and final node on the list
39884  const unsigned nnodes_root = root_face_ele_pt->nnode();
39885  Node *first_node_pt = root_face_ele_pt->node_pt(0);
39886  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
39887 
39888  // Push back on the list the new nodes
39889  sorted_nodes.push_back(first_node_pt);
39890  sorted_nodes.push_back(last_node_pt);
39891 
39892  // Store the bulk elements of the current face
39893  sorted_shared_bound_elements_pt.push_back(
39894  unsorted_shared_bulk_ele_pt[0][0]);
39895  sorted_shared_bound_elements_pt.push_back(
39896  unsorted_shared_bulk_ele_pt[0][1]);
39897 
39898  // Sort the face elements
39899  while (nsorted_face_ele < nnonhalo_face_shared_ele)
39900  {
39901  // Flag to indicate when a node was added
39902  bool node_added = false;
39903 
39904  // Start from the next edge since we have already added the
39905  // previous one as the initial face element
39906  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
39907  {
39908  FiniteElement* tmp_shared_face_ele_pt =
39909  nonhalo_shared_face_ele_pt[iface];
39910 
39911  // If face has not been sorted
39912  if (!shared_face_done[tmp_shared_face_ele_pt])
39913  {
39914  // Get the number of nodes for the current face element
39915  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
39916 
39917  // Get each individual node
39918  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
39919  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
39920 
39921  if (left_node_pt == first_node_pt)
39922  {
39923  // Push front the new node
39924  sorted_nodes.push_front(right_node_pt);
39925  first_node_pt = right_node_pt;
39926  node_added = true;
39927 
39928  // Store the elements of the current face element
39929  sorted_shared_bound_elements_pt.push_front(
39930  unsorted_shared_bulk_ele_pt[iface][1]);
39931  sorted_shared_bound_elements_pt.push_front(
39932  unsorted_shared_bulk_ele_pt[iface][0]);
39933  }
39934  else if (left_node_pt == last_node_pt)
39935  {
39936  // Push back the new node
39937  sorted_nodes.push_back(right_node_pt);
39938  last_node_pt = right_node_pt;
39939  node_added = true;
39940 
39941  // Store the elements of the current face element
39942  sorted_shared_bound_elements_pt.push_back(
39943  unsorted_shared_bulk_ele_pt[iface][0]);
39944  sorted_shared_bound_elements_pt.push_back(
39945  unsorted_shared_bulk_ele_pt[iface][1]);
39946  }
39947  else if (right_node_pt == first_node_pt)
39948  {
39949  // Push front the new node
39950  sorted_nodes.push_front(left_node_pt);
39951  first_node_pt = left_node_pt;
39952  node_added = true;
39953 
39954  // Store the elements of the current face element
39955  sorted_shared_bound_elements_pt.push_front(
39956  unsorted_shared_bulk_ele_pt[iface][1]);
39957  sorted_shared_bound_elements_pt.push_front(
39958  unsorted_shared_bulk_ele_pt[iface][0]);
39959  }
39960  else if (right_node_pt == last_node_pt)
39961  {
39962  // Push back the new node
39963  sorted_nodes.push_back(left_node_pt);
39964  last_node_pt = left_node_pt;
39965  node_added = true;
39966 
39967  // Store the elements of the current face element
39968  sorted_shared_bound_elements_pt.push_back(
39969  unsorted_shared_bulk_ele_pt[iface][0]);
39970  sorted_shared_bound_elements_pt.push_back(
39971  unsorted_shared_bulk_ele_pt[iface][1]);
39972  }
39973 
39974  if (node_added)
39975  {
39976  // Mark as done if one of its nodes has been added to the
39977  // list
39978  shared_face_done[tmp_shared_face_ele_pt] = true;
39979  nsorted_face_ele++;
39980 
39981  // Break the for
39982  break;
39983  }
39984 
39985  } // if (!shared_face_done[tmp_shared_face_ele_pt])
39986 
39987  } // for (iface < nnonhalo_face_shared_ele)
39988 
39989  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
39990 
39991  // ----------------------------------------------------------------
39992  // Here we can safely delete the face elements, they are no longer
39993  // required
39994 
39995  // First the nonhalo face elements
39996  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39997  {
39998  delete nonhalo_shared_face_ele_pt[inh];
39999  nonhalo_shared_face_ele_pt[inh] = 0;
40000  } // for (inh < nnonhalo_face_shared_ele)
40001 
40002  // ... then the halo face elements
40003  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40004  {
40005  delete halo_shared_face_ele_pt[ih];
40006  halo_shared_face_ele_pt[ih] = 0;
40007  } // for (inh < nhalo_face_shared_ele)
40008 
40009  // ------------------------------------------------------------------
40010  // At this point we already have a sorted list of nodes, get the
40011  // vertices from them and store them in a vector container
40012 
40013  // Get the number of nodes on the list
40014  const unsigned n_nodes = sorted_nodes.size();
40015 
40016  // The vector to store the vertices
40017  Vector<Vector<double> > polyline_vertices(n_nodes);
40018 
40019  // Copy the vertices from the nodes
40020  unsigned counter = 0;
40021  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40022  it_nodes != sorted_nodes.end();
40023  it_nodes++)
40024  {
40025  polyline_vertices[counter].resize(2);
40026  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40027  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40028  counter++;
40029  }
40030 
40031  // ------------------------------------------------------------------
40032  // Now get the target areas associated to the shared boundary
40033  // elements
40034 
40035  // Copy the sorted elements in a vector
40036  Vector<FiniteElement*> sorted_shared_ele_pt;
40037  for (std::list<FiniteElement*>::iterator it_ele =
40038  sorted_shared_bound_elements_pt.begin();
40039  it_ele != sorted_shared_bound_elements_pt.end();
40040  it_ele++)
40041  {sorted_shared_ele_pt.push_back((*it_ele));}
40042 
40043  // Get the number of target areas
40044  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40045  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40046 
40047  // Mark those shared elements already found
40048  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40049 
40050  // Counter for the number of already done shared elements
40051  unsigned count_found_shared_element = 0;
40052 
40053  // Get the target area associated to the shared boundary elements
40054  const unsigned nele = this->nelement();
40055 
40056  // Loop over the elements to find the target areas associated to
40057  // the shared boundary elements
40058  for (unsigned e = 0; e < nele; e++)
40059  {
40060  GeneralisedElement* current_ele_pt = this->element_pt(e);
40061  // Now compare the current element with those in the sorted
40062  // shared element array
40063  for (unsigned s = 0; s < n_shared_target_areas; s++)
40064  {
40065  // Get the element
40066  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40067  // Create the pair element-index to check if done
40068  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40069  std::make_pair(current_shared_ele_pt, s);
40070  if (!shared_ele_done[pair_gen_ele_idx])
40071  {
40072  // Compare with the global element
40073  if (current_ele_pt == current_shared_ele_pt)
40074  {
40075  // Store the target area of the current shared element
40076  sorted_shared_target_areas[s] = target_areas[e];
40077  // Mark the shared element as done
40078  shared_ele_done[pair_gen_ele_idx] = true;
40079  // Increase the number of found elements
40080  count_found_shared_element++;
40081  } // if (current_ele_pt == current_shared_ele_pt)
40082  } // if (!shared_ele_done[current_shared_ele_pt])
40083  } // for (s < nshared_taget_areas)
40084 
40085  // Check if all shared elements have been found
40086  if (count_found_shared_element == n_shared_target_areas)
40087  {break;}
40088 
40089  } // for (e < nele)
40090 
40091 #ifdef PARANOID
40092  // Check if the number of found target areas is the same as the
40093  // number of shared target areas
40094  if (count_found_shared_element != n_shared_target_areas)
40095  {
40096  std::ostringstream error_message;
40097  error_message
40098  << "The number of found target areas ("
40099  << count_found_shared_element << ") is different from the "
40100  << "total number\nof target areas ("
40101  << n_shared_target_areas << ") in shared boundary ("
40102  << shd_bnd_id <<")\n\n";
40103  throw OomphLibError(error_message.str(),
40104  OOMPH_CURRENT_FUNCTION,
40105  OOMPH_EXCEPTION_LOCATION);
40106  }
40107 #endif
40108 
40109  // The number of vertices
40110  const unsigned n_vertices = n_nodes;
40111 
40112  // Get the number of segments from the input vector_polyline_pt
40113  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40114  // Get the number of segments from the input vector_polyline_pt to
40115  // ensure that the shared boundary corresponds to the one
40116  // represented by the shared face elements (this has sence when the
40117  // mesh was re-created from re-starting)
40118 
40119  // Check that the number of vertices correspond with the number of
40120  // segments
40121 #ifdef PARANOID
40122  if (n_segments != n_vertices-1)
40123  {
40124  std::ostringstream error_message;
40125  error_message
40126  << "The number of segments from the current shared polyline "
40127  << "(" << n_segments << ") does not\ncorrespond with the number of "
40128  << "sorted vertices (" << n_vertices-1 << ") of the current shared\n"
40129  << "boundary\n\n";
40130  throw OomphLibError(error_message.str(),
40131  OOMPH_CURRENT_FUNCTION,
40132  OOMPH_EXCEPTION_LOCATION);
40133  }
40134 
40135  // Check that the number of target areas correspond with the number
40136  // of vertices
40137  if (n_segments != n_shared_target_areas/2)
40138  {
40139  std::ostringstream error_message;
40140  error_message
40141  << "The number of segments for the current sorting of edges "
40142  << "(" << n_segments << ") is different\nfrom the number of "
40143  << "target areas (" << n_shared_target_areas/2 << ")\n\n";
40144  throw OomphLibError(error_message.str(),
40145  OOMPH_CURRENT_FUNCTION,
40146  OOMPH_EXCEPTION_LOCATION);
40147  }
40148 #endif
40149 
40150  // ------------------------------------------------------------------
40151  // Get the target areas that are used to perform the unrefinement
40152  // and refinement operation. For each face element on a shared
40153  // polyline there are two bulk elements, a halo and a haloed
40154  // element, each with an associated target area. Review the
40155  // function
40156  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40157  // check how the shared boundaries were created
40158  Vector<double> polyline_target_area(n_segments);
40159  // Loop over the segments in the shared polyline
40160  for (unsigned s = 0; s < n_segments; s++)
40161  {
40162  // Get the minimum of the associated target areas
40163  polyline_target_area[s] = std::min(sorted_shared_target_areas[s*2],
40164  sorted_shared_target_areas[(s*2)+1]);
40165  }
40166 
40167  // Before going to the unrefinement or refinement process check
40168  // that in all processors where the shared boundary lives start
40169  // from the same vertex.
40170  // Start from the bottom left vertex
40171  if (polyline_vertices[n_vertices-1][1] < polyline_vertices[0][1])
40172  {
40173  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40174  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40175  }
40176  else if (polyline_vertices[n_vertices-1][1] == polyline_vertices[0][1])
40177  {
40178  if (polyline_vertices[n_vertices-1][0] < polyline_vertices[0][0])
40179  {
40180  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40181  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40182  }
40183  }
40184 
40185  // ------------------------------------------------------------------
40186  // Apply unrefinement
40187  bool unrefinement_applied = false;
40188  // Apply unefinement if there are more than three nodes at the
40189  // shared boundary
40190  if (n_vertices > 3)
40191  {
40192  unrefinement_applied =
40193  unrefine_shared_boundary_constrained_by_target_area(
40194  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40195  }
40196 
40197  // Apply refinement
40198  bool refinement_applied =
40199  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40200  polyline_target_area);
40201 
40202  // Was unrefinement/refinement applied
40203  update_was_performed |= (unrefinement_applied || refinement_applied);
40204 
40205  // ------------------------------------------------------------------
40206  // Update the polyline representation of the shared boundary
40207 
40208  // The new shared polyline representation
40209  TriangleMeshPolyLine *new_polyline_pt =
40210  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40211 
40212  // Get the curve section representation
40213  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
40214 
40215  // Copy the connection information from the old shared polyline to
40216  // the new one
40217  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40218 
40219  // Now update the polyline according to the new vertices but first
40220  // check if the object is allowed to delete the representation or
40221  // if it should be done by other object
40222  bool delete_it_on_destructor = false;
40223 
40224  // Establish the element as being deleted by the destructor of the
40225  // class
40226  std::set<TriangleMeshCurveSection*>::iterator it =
40227  this->Free_curve_section_pt.find(curve_section_pt);
40228 
40229  if (it!=this->Free_curve_section_pt.end())
40230  {
40231  this->Free_curve_section_pt.erase(it);
40232  delete curve_section_pt;
40233  delete_it_on_destructor = true;
40234  }
40235 
40236  // Copy the new representation to the output vector_polyline_pt
40237  vector_polyline_pt[pp] = new_polyline_pt;
40238 
40239  // Get the new curve section representation
40240  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
40241 
40242  // Update the Boundary - Polyline map
40243  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40244 
40245  if (delete_it_on_destructor)
40246  {
40247  this->Free_curve_section_pt.insert(new_curve_section_pt);
40248  }
40249 
40250  } // for (pp < npoly)
40251 
40252  return update_was_performed;
40253 
40254 }
40255 #endif // #ifdef OOMPH_HAS_MPI
40256 
40257  //=========================================================================
40258  /// \short Helper function that performs the unrefinement process
40259  /// on the specified boundary by using the provided vertices
40260  /// representation and the associated target area.
40261  //=========================================================================
40262  template<class ELEMENT>
40265  const unsigned &c,
40266  Vector<Vector<double> >
40267  &vector_bnd_vertices,
40268  double &unrefinement_tolerance,
40269  Vector<double> &area_constraint)
40270  {
40271  // Store the vertices not allowed for deletion
40272  std::set<Vector<double> > no_delete_vertex;
40273 
40274  // Does the boundary receives connections?
40275  const bool boundary_receive_connections =
40276  this->boundary_connections(b, c, no_delete_vertex);
40277 
40278  // Boolean that indicates whether an actual update of the vertex
40279  // coordinates was performed
40280  bool unrefinement_applied = false;
40281 
40282  // Return inmedately
40283  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40284  {
40285  return unrefinement_applied;
40286  }
40287 
40288  // Strategy to delete nodes: Consider the target area of the
40289  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40290  // if the number of segments to be added is equal to zero for both
40291  // elements then compute the average of both target areas and check
40292  // if the number of segments is still zero, if that holds mark the
40293  // node to be deleted. Before delete the node check whether it is in
40294  // the non_delete_vertex list. Skip the i+1-th node and go for the
40295  // (i+2)-th one, it means, increase the counter for current node by
40296  // two.
40297 
40298  // Number of vertices on the boundary
40299  unsigned n_vertex = vector_bnd_vertices.size();
40300 
40301  // Compute a constant value
40302  const double constant_value = 4.0/sqrt(3.0);
40303 
40304  if (n_vertex > 2)
40305  {
40306  // Go through all the vertices and delete points when the target area
40307  // indicates zero points along the boundary
40308  for (unsigned i = 1; i < n_vertex-1; i+=2)
40309  {
40310  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40311  {
40312  const double local_zeta_first = vector_bnd_vertices[i-1][0];
40313  const double local_zeta_last = vector_bnd_vertices[i+1][0];
40314  const double local_length_zeta =
40315  std::fabs(local_zeta_last-local_zeta_first);
40316 
40317  const double x1 = vector_bnd_vertices[i-1][1];
40318  const double y1 = vector_bnd_vertices[i-1][2];
40319  const double x2 = vector_bnd_vertices[i+1][1];
40320  const double y2 = vector_bnd_vertices[i+1][2];
40321  const double local_length =
40322  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40323 
40324  const double x_m = vector_bnd_vertices[i][1];
40325  const double y_m = vector_bnd_vertices[i][2];
40326 
40327  const double average_area_constraint =
40328  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40329 
40330  // Compute the length of the the side of an equilateral
40331  // triangle
40332  const double length_side =
40333  sqrt(constant_value*average_area_constraint);
40334 
40335  const double length_side_zeta =
40336  (local_length_zeta * length_side) / local_length;
40337 
40338  // Is the new length greater that the old one
40339  if ((length_side_zeta / local_length_zeta) > 1.0)
40340  {
40341  // If the number of segments is zero then verify the condition for
40342  // deletion of nodes but using the condition in the default
40343  // unrefine_boundary() method. If both conditions are true then
40344  // delete the node
40345  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40346  double a_x=vector_bnd_vertices[i-1][1];
40347  double a_y=vector_bnd_vertices[i-1][2];
40348  double b_x=vector_bnd_vertices[i][1];
40349  double b_y=vector_bnd_vertices[i][2];
40350  double c_x=vector_bnd_vertices[i+1][1];
40351  double c_y=vector_bnd_vertices[i+1][2];
40352 
40353  double a=b_x-a_x;
40354  double b=b_y-a_y;
40355  double c=c_x-a_x;
40356  double d=c_y-a_y;
40357 
40358  double e=a*(a_x+b_x)+b*(a_y+b_y);
40359  double f=c*(a_x+c_x)+d*(a_y+c_y);
40360 
40361  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
40362 
40363  bool do_it=false;
40364  if (std::fabs(g)<1.0e-14)
40365  {
40366  do_it=true;
40367  }
40368  else
40369  {
40370  double p_x=(d*e-b*f)/g;
40371  double p_y=(a*f-c*e)/g;
40372 
40373  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
40374 
40375  double rhalfca_x=0.5*(a_x-c_x);
40376  double rhalfca_y=0.5*(a_y-c_y);
40377 
40378  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
40379 
40380  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
40381 
40382  // If sticky out bit divided by distance between end nodes
40383  // is less than tolerance the boundary is so flat that we
40384  // can safely kill the node
40385  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
40386  unrefinement_tolerance)
40387  {
40388  do_it=true;
40389  }
40390  }
40391 
40392  // If the vertex was proposed for deletion check if it is
40393  // allowed for being deleted
40394  if (do_it && boundary_receive_connections)
40395  {
40396  // Is the vertex one of the non deletable vertices
40397  for (std::set<Vector<double> >::iterator it =
40398  no_delete_vertex.begin();
40399  it != no_delete_vertex.end(); it++)
40400  {
40401  // Compute the distance between the proposed node to
40402  // delete and the ones that should not be deleted
40403  const double x = (*it)[0];
40404  const double y = (*it)[1];
40405  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40406  error = sqrt(error);
40407 
40408  if(error <
40409  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40410  {
40411  // Do not delete the vertex
40412  do_it = false;
40413  break;
40414  }
40415 
40416  }
40417 
40418  } // if (do_it && boundary_receive_connections)
40419 
40420  // Remove node?
40421  if (do_it)
40422  {
40423  vector_bnd_vertices[i].resize(0);
40424  }
40425  } // if (n_seg == 0)
40426  } // if (area_constraint[i] >= 0)
40427  } // for (i < n_vertex-1)
40428 
40429  // Create a new (temporary) vector for the nodes, so that deleted nodes
40430  // are not stored
40431  Vector<Vector<double> > compact_vector;
40432 
40433  // Compact vector for target areas too
40434  Vector<double> compact_area_constraint;
40435 
40436  // Copy only the non deleted nodes
40437  for(unsigned i = 0; i < n_vertex; i++)
40438  {
40439  // If the entry was not deleted include it in the new vector
40440  if (vector_bnd_vertices[i].size()!=0)
40441  {
40442  compact_vector.push_back(vector_bnd_vertices[i]);
40443  }
40444  }
40445 
40446  // ------------------------------------------------------------------
40447  // Size of the target areas vector
40448  unsigned nsize_target = area_constraint.size();
40449  if (nsize_target == 1)
40450  {
40451  // No node was deleted, just copy the target area
40452  compact_area_constraint.push_back(area_constraint[0]);
40453  }
40454 
40455  // Copy the target areas
40456  for(unsigned i = 1; i < n_vertex; i+=2)
40457  {
40458  // If the entry was not deleted include the target areas of both
40459  // elements sharing the node
40460  if (vector_bnd_vertices[i].size()!=0)
40461  {
40462  compact_area_constraint.push_back(area_constraint[i-1]);
40463  // To catch the case when working with even number of vertex
40464  if (i < nsize_target)
40465  {
40466  compact_area_constraint.push_back(area_constraint[i]);
40467  }
40468  }
40469  else
40470  {
40471  // If the node was deleted then compute the new target area as the
40472  // average of the target area of the elements sharing the node
40473  double new_area_constraint =
40474  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40475  compact_area_constraint.push_back(new_area_constraint);
40476  }
40477  }
40478 
40479  // If the size of the compact vector is different from the size of the
40480  // vector before applying the area length constraint then the polyline
40481  // was updated
40482  if( n_vertex != compact_vector.size() )
40483  {
40484  unrefinement_applied = true;
40485  }
40486 
40487  // Copy back to the original vector
40488  n_vertex = compact_vector.size();
40489  vector_bnd_vertices.resize(n_vertex);
40490  for(unsigned i = 0; i < n_vertex; i++)
40491  {
40492  vector_bnd_vertices[i].resize(3);
40493  vector_bnd_vertices[i][0] = compact_vector[i][0];
40494  vector_bnd_vertices[i][1] = compact_vector[i][1];
40495  vector_bnd_vertices[i][2] = compact_vector[i][2];
40496  }
40497 
40498  // Copy back to the original vector of target areas
40499  unsigned ntarget_areas = compact_area_constraint.size();
40500  area_constraint.resize(ntarget_areas);
40501  for(unsigned i = 0; i < ntarget_areas; i++)
40502  {
40503  area_constraint[i] = compact_area_constraint[i];
40504  }
40505 
40506  } // if (n_vertex > 2)
40507 
40508  return unrefinement_applied;
40509 
40510  }
40511 
40512  //=========================================================================
40513  /// \short Helper function that performs the refinement process
40514  /// on the specified boundary by using the provided vertices
40515  /// representation and the associated elements target area.
40516  //=========================================================================
40517  template<class ELEMENT>
40520  mesh_geom_obj_pt,
40521  Vector<Vector<double> >
40522  &vector_bnd_vertices,
40523  double &refinement_tolerance,
40524  Vector<double> &area_constraint)
40525  {
40526  // Boolean that indicates whether an actual update of the vertex
40527  // coordinates was performed
40528  bool refinement_applied = false;
40529 
40530  // Return inmedately
40531  if (!Do_boundary_refinement_constrained_by_target_areas)
40532  {
40533  return refinement_applied;
40534  }
40535 
40536  // Get the total number of current vertices
40537  unsigned n_vertex=vector_bnd_vertices.size();
40538 
40539  // Compute a constant value
40540  const double constant_value = 4.0/sqrt(3.0);
40541 
40542  if (n_vertex > 1)
40543  {
40544  // Create a new (temporary) vector for the nodes, so that new
40545  // nodes can be stored
40546  Vector<Vector<double> > new_vector;
40547 
40548  // Go through all the vertices and create points according to the
40549  // specified element area
40550  for (unsigned i = 0; i < n_vertex-1; i++)
40551  {
40552  // Include the first node
40553  new_vector.push_back(vector_bnd_vertices[i]);
40554 
40555  if (area_constraint[i] > 0)
40556  {
40557  double local_zeta_first = vector_bnd_vertices[i][0];
40558  double local_zeta_last = vector_bnd_vertices[i+1][0];
40559  const double local_length_zeta =
40560  std::fabs(local_zeta_last-local_zeta_first);
40561 
40562  // Check if need to interchange the zeta first and the zeta
40563  // last (to ensure the same order in zeta values in any two
40564  // processors)
40565  if (local_zeta_first > local_zeta_last)
40566  {
40567  const double tmp_zeta = local_zeta_first;
40568  local_zeta_first = local_zeta_last;
40569  local_zeta_last = tmp_zeta;
40570  }
40571 
40572  const double x1 = vector_bnd_vertices[i][1];
40573  const double y1 = vector_bnd_vertices[i][2];
40574  const double x2 = vector_bnd_vertices[i+1][1];
40575  const double y2 = vector_bnd_vertices[i+1][2];
40576  const double local_length =
40577  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40578 
40579  // Compute the length in zeta units
40580  const double length_side = sqrt(constant_value*area_constraint[i]);
40581  const double length_side_zeta =
40582  (local_length_zeta * length_side) / local_length;
40583 
40584  // How many segments should be introduced
40585  const double n_seg_double = length_side_zeta/local_length_zeta;
40586 
40587  // One segment initialy (the original one)
40588  unsigned n_seg = 1;
40589 
40590  // How many more segments to introduce?
40591  n_seg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40592 
40593  // Are there segments to introduce? There must be at least one
40594  // segment, the original one
40595  if (n_seg > 0)
40596  {
40597  // The zeta increment
40598  double zeta_increment = (local_length_zeta)/((double)n_seg);
40599 
40600  Vector<double> zeta(1);
40601  // Create the n_seg segmets between each pair of nodes
40602  for(unsigned s=1;s<n_seg;s++)
40603  {
40604  // Get the coordinates
40605  zeta[0]= local_zeta_first + zeta_increment*double(s);
40606  Vector<double> vertex(2);
40607  mesh_geom_obj_pt->position(zeta, vertex);
40608 
40609  // Create the new node
40610  Vector<double> new_node(3);
40611  new_node[0]=zeta[0];
40612  new_node[1]=vertex[0];
40613  new_node[2]=vertex[1];
40614 
40615  // Include the new node
40616  new_vector.push_back(new_node);
40617 
40618  } // for (s<=n_seg)
40619 
40620  } // if (n_seg > 0)
40621 
40622  } // if (area_constraint[i] >= 0)
40623 
40624  } // for (i < n_vertex-1)
40625 
40626  // Once finished all the vertices add the last node to the vector
40627  new_vector.push_back(vector_bnd_vertices[n_vertex-1]);
40628 
40629  // If the new size of the vector (including the added nodes) is
40630  // different from the size of the vector before applying the
40631  // area length constraint then the polyline was updated
40632  n_vertex=new_vector.size();
40633  if( n_vertex != vector_bnd_vertices.size() )
40634  {
40635  refinement_applied = true;
40636  }
40637 
40638  // Copy the new representation
40639  vector_bnd_vertices.resize(n_vertex);
40640  for(unsigned i=0;i<n_vertex;i++)
40641  {
40642  vector_bnd_vertices[i].resize(3);
40643  vector_bnd_vertices[i][0]=new_vector[i][0];
40644  vector_bnd_vertices[i][1]=new_vector[i][1];
40645  vector_bnd_vertices[i][2]=new_vector[i][2];
40646  }
40647 
40648  } // if (n_vertex > 1)
40649 
40650  return refinement_applied;
40651 
40652  }
40653 
40654  //======================================================================
40655  /// \short Helper function that performs the unrefinement process
40656  /// on the specified boundary by using the provided vertices
40657  /// representation and the associated target area.
40658  /// NOTE: This is the version that applies unrefinement to shared
40659  /// boundaries
40660  //======================================================================
40661  template <class ELEMENT>
40664  const unsigned &b,
40665  const unsigned &c,
40666  Vector<Vector<double> > &vector_bnd_vertices,
40667  Vector<double> &area_constraint)
40668  {
40669  // Store the vertices not allowed for deletion
40670  std::set<Vector<double> > no_delete_vertex;
40671 
40672  // Does the boundary receives connections?
40673  const bool boundary_receive_connections =
40674  this->boundary_connections(b, c, no_delete_vertex);
40675 
40676  // Boolean that indicates whether an actual update of the vertex
40677  // coordinates was performed
40678  bool unrefinement_applied = false;
40679 
40680  // Return inmedately
40681  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40682  {
40683  return unrefinement_applied;
40684  }
40685 
40686  // Strategy to delete nodes:
40687 
40688  // Strategy to delete nodes: Consider the target area of the
40689  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40690  // if the number of segments to be added is equal to zero for both
40691  // elements then compute the average of both target areas and check
40692  // if the number of segments is still zero, if that holds mark the
40693  // node to be deleted. Before delete the node check whether it is in
40694  // the non_delete_vertex list. Skip the i+1-th node and go for the
40695  // (i+2)-th one, it means, increase the counter for current node by
40696  // two.
40697 
40698  // Number of vertices on the boundary
40699  unsigned n_vertex = vector_bnd_vertices.size();
40700 
40701  // Compute a constant value
40702  const double constant_value = 4.0/sqrt(3.0);
40703 
40704  if (n_vertex > 2)
40705  {
40706  // Go through all the vertices and delete points when the target
40707  // area indicates zero points along the boundary
40708  for (unsigned i = 1; i < n_vertex-1; i+=2)
40709  {
40710  // Is a target area assigned to the left and right element of
40711  // the i-th node
40712  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40713  {
40714  // Get the vertices to the left
40715  const double x1 = vector_bnd_vertices[i-1][0];
40716  const double y1 = vector_bnd_vertices[i-1][1];
40717  // ... and to the right of the i-th vertex
40718  const double x2 = vector_bnd_vertices[i+1][0];
40719  const double y2 = vector_bnd_vertices[i+1][1];
40720 
40721  // The distance
40722  const double local_length =
40723  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40724 
40725  // Get the middle vertex
40726  const double x_m = vector_bnd_vertices[i][0];
40727  const double y_m = vector_bnd_vertices[i][1];
40728 
40729  // The average area
40730  const double average_area_constraint =
40731  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40732 
40733  // Compute the base length of the triangle with
40734  // area_constraint area
40735  const double length_side =
40736  sqrt(constant_value*average_area_constraint);
40737 
40738  // Is the new length greater than the old one
40739  if ((length_side / local_length) > 1.0)
40740  {
40741  bool do_it=true;
40742 
40743  // If the vertex was proposed for deletion check that it is
40744  // allowed for being deleted
40745  if (do_it && boundary_receive_connections)
40746  {
40747  // Is the vertex one of the non deletable vertices
40748  for (std::set<Vector<double> >::iterator it =
40749  no_delete_vertex.begin();
40750  it != no_delete_vertex.end(); it++)
40751  {
40752  // Compute the distance between the proposed node to delete
40753  // and the ones that should not be deleted
40754  const double x = (*it)[0];
40755  const double y = (*it)[1];
40756  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40757  error = sqrt(error);
40758 
40759  if(error <
40760  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40761  {
40762  // Do not delete the vertex
40763  do_it = false;
40764  break;
40765  }
40766 
40767  }
40768 
40769  } // if (do_it && boundary_receive_connections)
40770 
40771  // Remove node?
40772  if (do_it)
40773  {
40774  vector_bnd_vertices[i].resize(0);
40775  }
40776  } // if ((local_length / length_side) <= 1.3)
40777 
40778  } // if (area_constraint[i] >= 0)
40779 
40780  } // for (i < n_vertex-1)
40781 
40782  // Create a new (temporary) vector for the nodes, so that deleted nodes
40783  // are not stored
40784  Vector<Vector<double> > compact_vector;
40785 
40786  // Compact vector for target areas too
40787  Vector<double> compact_area_constraint;
40788 
40789  // Copy only the non deleted nodes
40790  for(unsigned i = 0; i < n_vertex; i++)
40791  {
40792  // If the entry was not deleted include it in the new vector
40793  if (vector_bnd_vertices[i].size()!=0)
40794  {
40795  compact_vector.push_back(vector_bnd_vertices[i]);
40796  }
40797  }
40798 
40799  // ------------------------------------------------------------------
40800  // The number of target areas
40801  unsigned n_area_constraint = area_constraint.size();
40802  if (n_area_constraint == 1)
40803  {
40804  // No node could be deleted then just copy the target area
40805  compact_area_constraint.push_back(area_constraint[0]);
40806  }
40807 
40808  // Copy the target areas
40809  for(unsigned i = 1; i < n_vertex; i+=2)
40810  {
40811  // If the entry was not deleted include the target areas of both
40812  // elements sharing the node
40813  if (vector_bnd_vertices[i].size()!=0)
40814  {
40815  compact_area_constraint.push_back(area_constraint[i-1]);
40816  // To catch the case when working with even number of vertices
40817  if (i < n_area_constraint)
40818  {
40819  compact_area_constraint.push_back(area_constraint[i]);
40820  }
40821  }
40822  else
40823  {
40824  // If the node was deleted then compute the new target area as the
40825  // average of the target area of the elements sharing the node
40826  const double new_area_constraint =
40827  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40828  compact_area_constraint.push_back(new_area_constraint);
40829  }
40830  } // for (i < n_vertex)
40831 
40832  // If the size of the compact vector is different from the size of
40833  // the vector before applying the area length constraint then the
40834  // polyline was updated
40835  if( n_vertex != compact_vector.size() )
40836  {
40837  unrefinement_applied = true;
40838  }
40839 
40840  // Copy back to the original vector
40841  n_vertex = compact_vector.size();
40842  vector_bnd_vertices.resize(n_vertex);
40843  for(unsigned i = 0; i < n_vertex; i++)
40844  {
40845  vector_bnd_vertices[i].resize(2);
40846  vector_bnd_vertices[i][0] = compact_vector[i][0];
40847  vector_bnd_vertices[i][1] = compact_vector[i][1];
40848  }
40849 
40850  // Copy back to the original vector of target areas
40851  unsigned ntarget_areas = compact_area_constraint.size();
40852  area_constraint.resize(ntarget_areas);
40853  for(unsigned i = 0; i < ntarget_areas; i++)
40854  {
40855  area_constraint[i] = compact_area_constraint[i];
40856  }
40857 
40858  } // if (n_vertex > 2)
40859 
40860  return unrefinement_applied;
40861 
40862  }
40863 
40864  //======================================================================
40865  /// \short Helper function that performs the refinement process
40866  /// on the specified boundary by using the provided vertices
40867  /// representation and the associated elements target area.
40868  /// NOTE: This is the version that applies refinement to shared
40869  /// boundaries
40870  //======================================================================
40871  template <class ELEMENT>
40874  Vector<Vector<double> > &vector_bnd_vertices,
40875  Vector<double> &area_constraint)
40876  {
40877  // Boolean that indicates whether an actual update of the vertex
40878  // coordinates was performed
40879  bool refinement_applied = false;
40880 
40881  // Return inmedately
40882  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
40883  {
40884  return refinement_applied;
40885  }
40886 
40887  // Get the number of segments
40888  unsigned nsegments = vector_bnd_vertices.size() - 1;
40889 
40890  // Create a new (temporary) vector for the nodes, so that new nodes
40891  // can be stored
40892  Vector<Vector<double> > tmp_bnd_vertices;
40893 
40894  // Compute a constant value
40895  const double constant_value = 4.0/sqrt(3.0);
40896 
40897  for (unsigned s = 0; s < nsegments; s++)
40898  {
40899  Vector<double> left_vertex = vector_bnd_vertices[s];
40900  Vector<double> right_vertex = vector_bnd_vertices[s+1];
40901 
40902  // Initial and final point of the segment
40903  const double x1 = left_vertex[0];
40904  const double y1 = left_vertex[1];
40905  const double x2 = right_vertex[0];
40906  const double y2 = right_vertex[1];
40907 
40908  // Lenght of the segment
40909  const double segment_length =
40910  sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
40911 
40912  // Compute the distance for the new segments
40913  const double new_segment_length =
40914  sqrt(constant_value*area_constraint[s]);
40915 
40916  // How many segments should be introduced
40917  const double n_seg_double = new_segment_length / segment_length;
40918 
40919  // One segment initialy (the original one)
40920  unsigned nseg = 1;
40921  // How many more segments to introduce?
40922  nseg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40923 
40924  // The left vertex must be always included, even though no new vertex
40925  // be added
40926  tmp_bnd_vertices.push_back(left_vertex);
40927 
40928  // Are there segments to introduce? There must be at least one
40929  // segment, the original one
40930  if (nseg > 0)
40931  {
40932  // Create intermediate vertices
40933  double incrementx = (right_vertex[0] - left_vertex[0])/(double)(nseg);
40934  double incrementy = (right_vertex[1] - left_vertex[1])/(double)(nseg);
40935  for (unsigned i = 1; i < nseg; i++)
40936  {
40937  Vector<double> tmp_vertex(2);
40938  tmp_vertex[0] = left_vertex[0] + incrementx*i;
40939  tmp_vertex[1] = left_vertex[1] + incrementy*i;
40940  tmp_bnd_vertices.push_back(tmp_vertex);
40941  } // for (i < nseg)
40942 
40943  } // if (nseg > 0)
40944 
40945  } // for (s < nsegments)
40946 
40947  // Add the last vertex
40948  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
40949 
40950  // If the new size of the vector (including the added nodes) is
40951  // different from the size of the vector before applying the
40952  // refinement then the polyline was updated
40953  nsegments = tmp_bnd_vertices.size() - 1;
40954  if( nsegments != vector_bnd_vertices.size() - 1 )
40955  {
40956  refinement_applied = true;
40957 
40958  // Copy across
40959  vector_bnd_vertices.resize(nsegments + 1);
40960  for(unsigned i = 0; i < nsegments + 1; i++)
40961  {
40962  vector_bnd_vertices[i].resize(2);
40963  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
40964  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
40965  }
40966  }
40967 
40968  return refinement_applied;
40969 
40970  }
40971 
40972 //======================================================================
40973 /// \short Updates the polylines representation after restart
40974 //======================================================================
40975 template <class ELEMENT>
40977 update_polygon_after_restart(TriangleMeshPolygon* &polygon_pt)
40978 {
40979 
40980  // **********************************************************************
40981  // 1) Collect the elements adjacet to the polyline boundary id and
40982  // update the polyline
40983  // **********************************************************************
40984 
40985  // (1.1) Get the face mesh representation
40986  Vector<Mesh*> face_mesh_pt;
40987  get_face_mesh_representation(polygon_pt,face_mesh_pt);
40988 
40989  // (1.2) Create vertices of the polylines by using the vertices of the
40990  // FaceElements
40991  Vector<double> vertex_coord(3); // zeta,x,y
40992  Vector<double> bound_left(1);
40993  Vector<double> bound_right(1);
40994 
40995  const unsigned n_polyline = polygon_pt->npolyline();
40996 
40997  // Go for each polyline
40998  for(unsigned p=0;p<n_polyline;p++)
40999  {
41000  // Get the MeshAsGeomObject representation just once per polyline,
41001  // this object is only used by the
41002  // refine_boundary_constrained_by_target_area() method. We get it here
41003  // to ensure that all processors (in a distributed context) get this
41004  // representation just once, and because an AllToAll MPI communication
41005  // is used in this calling
41006  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
41007 
41008  // Set of coordinates that are on the boundary
41009  // Set entries are ordered on first entry in vector which stores
41010  // the boundary coordinate so the vertices come out in order!
41011  std::set<Vector<double> > vertex_nodes;
41012 
41013  // Vector to store the vertices, transfer the sorted vertices from the
41014  // set to this vector, --- including the z-value ---
41015  Vector<Vector<double> > tmp_vector_vertex_node;
41016 
41017  // Vector to store the coordinates of the polylines, same as the
41018  // tmp_vector_vertex_node vector (after adding more nodes) but
41019  // --- without the z-value ---, used to re-generate the polylines
41020  Vector<Vector<double> > vector_vertex_node;
41021 
41022 #ifdef OOMPH_HAS_MPI
41023  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41024  // Set of coordinates that are on the boundary (splitted boundary version)
41025  // The first vector is used to allocate the points for each sub-boundary
41026  // Set entries are ordered on first entry in vector which stores
41027  // the boundary coordinate so the vertices come out in order!
41028  Vector<std::set<Vector<double> > >sub_vertex_nodes;
41029 
41030  // Vector to store the vertices, transfer the sorted vertices from the
41031  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41032  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
41033 
41034  // Vector to store the coordinates of the polylines that will represent
41035  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41036  // but --- without the z-value ---, used to generate the sub-polylines
41037  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41038  // --------- Stuff to deal with splitted boundaries ----------- End ------
41039 #endif
41040 
41041  //Get the boundary id
41042  unsigned bound=polygon_pt->curve_section_pt(p)->boundary_id();
41043 
41044  /// Use a vector of vector for vertices and target areas to
41045  /// deal with the cases when the boundaries are split by the
41046  /// distribution process
41047 
41048  // Loop over the face elements (ordered) and add their vertices
41049  const unsigned nface_element = face_mesh_pt[p]->nelement();
41050 
41051  // Store the non halo face elements, the ones from which we will
41052  // get the vertices
41053  Vector<FiniteElement*> non_halo_face_element_pt;
41054  // Map to store the index of the face element on a boundary
41055  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41056 
41057  for(unsigned ef=0;ef<nface_element;++ef)
41058  {
41059  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41060  // Skip the halo elements
41061 #ifdef OOMPH_HAS_MPI
41062  if (this->is_mesh_distributed())
41063  {
41064  // Only work with non-halo elements
41065  if (ele_face_pt->is_halo()) {continue;}
41066  }
41067 #endif
41068  // Add the face element to the vector
41069  non_halo_face_element_pt.push_back(ele_face_pt);
41070  face_element_index_on_boundary[ele_face_pt] = ef;
41071  }
41072 
41073  // Get the number of non halo face element
41074  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41075 
41076  // Map to know the already sorted face elements
41077  std::map<FiniteElement*,bool> face_element_done;
41078 
41079  // Number of done face elements
41080  unsigned nsorted_face_elements = 0;
41081 
41082 #ifdef OOMPH_HAS_MPI
41083  // Counter for sub_boundaries
41084  unsigned nsub_boundaries = 0;
41085 #endif // #ifdef OOMPH_HAS_MPI
41086 
41087  // Continue until all the face elements have been sorted
41088  // This while is to deal with the cases of splitted boundaries
41089  while(nsorted_face_elements < nnon_halo_face_element)
41090  {
41091  // Get and initial face element
41092  FiniteElement* ele_face_pt = 0;
41093 #ifdef PARANOID
41094  bool found_initial_face_element = false;
41095 #endif
41096 
41097  unsigned iface = 0;
41098  for (iface = 0; iface < nnon_halo_face_element; iface++)
41099  {
41100  ele_face_pt = non_halo_face_element_pt[iface];
41101  // If not done then take it as initial face element
41102  if (!face_element_done[ele_face_pt])
41103  {
41104 #ifdef PARANOID
41105  found_initial_face_element = true;
41106 #endif
41107  nsorted_face_elements++;
41108  iface++;
41109  break;
41110  }
41111  }
41112 
41113 #ifdef PARANOID
41114  if (!found_initial_face_element)
41115  {
41116  std::ostringstream error_message;
41117  error_message
41118  <<"Could not find an initial face element for the current segment\n";
41119  // << "----- Possible memory leak -----\n";
41120  throw OomphLibError(error_message.str(),
41121  "RefineableTriangleMesh::update_polygon_after_restart()",
41122  OOMPH_EXCEPTION_LOCATION);
41123  }
41124 #endif
41125 
41126  // Local set of coordinates that are on the boundary
41127  // Set entries are ordered on first entry in vector which stores
41128  // the boundary coordinate so the vertices come out in order!
41129  std::set<Vector<double> > local_vertex_nodes;
41130 
41131  // Vector to store the vertices, transfer the sorted vertices from the
41132  // set (local) to this vector (local), --- including the z-value ---
41133  Vector<Vector<double> > local_tmp_vector_vertex_node;
41134 
41135  // ------------------------------------------------------------------
41136  // ------------------------------------------------------------------
41137  // -----------------------------------------------------------------
41138  // Add the vertices of the initial face element to the set of local
41139  // sorted vertices
41140  // -----------------------------------------------------------------
41141  unsigned nnode = ele_face_pt->nnode();
41142  // Add the left-hand node to the set:
41143  // Boundary coordinate
41144  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
41145  vertex_coord[0] = bound_left[0];
41146 
41147  // Actual coordinates
41148  for(unsigned i=0;i<2;i++)
41149  {
41150  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
41151  }
41152  local_vertex_nodes.insert(vertex_coord);
41153 
41154  // Add the right-hand nodes to the set:
41155  // Boundary coordinate
41156  ele_face_pt->node_pt(nnode-1)->
41157  get_coordinates_on_boundary(bound,bound_right);
41158  vertex_coord[0] = bound_right[0];
41159 
41160  // Actual coordinates
41161  for(unsigned i=0;i<2;i++)
41162  {
41163  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
41164  }
41165  local_vertex_nodes.insert(vertex_coord);
41166 
41167  // The initial and final node on the set
41168  Node *first_node_pt = ele_face_pt->node_pt(0);
41169  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
41170 
41171  // Mark the current face element as done
41172  face_element_done[ele_face_pt] = true;
41173 
41174  // ------------------------------------------------------------------
41175  // ------------------------------------------------------------------
41176  // ------------------------------------------------------------------
41177 
41178  // Continue iterating if a new face element has been added to the
41179  // list
41180  bool face_element_added = false;
41181 
41182  // While a new face element has been added to the set of sorted
41183  // face elements then re-iterate
41184  do
41185  {
41186  // Start from the next face elements since we have already added
41187  // the previous one as the initial face element (any previous face
41188  // element had to be added on previous iterations)
41189  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
41190  {
41191  face_element_added = false;
41192  ele_face_pt = non_halo_face_element_pt[iiface];
41193  if (!face_element_done[ele_face_pt])
41194  {
41195  // Get each individual node to check if they are contiguous
41196  nnode = ele_face_pt->nnode();
41197  Node* left_node_pt = ele_face_pt->node_pt(0);
41198  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
41199 
41200  if (left_node_pt == first_node_pt)
41201  {
41202  first_node_pt = right_node_pt;
41203  face_element_added = true;
41204  }
41205  else if (left_node_pt == last_node_pt)
41206  {
41207  last_node_pt = right_node_pt;
41208  face_element_added = true;
41209  }
41210  else if (right_node_pt == first_node_pt)
41211  {
41212  first_node_pt = left_node_pt;
41213  face_element_added = true;
41214  }
41215  else if (right_node_pt == last_node_pt)
41216  {
41217  last_node_pt = left_node_pt;
41218  face_element_added = true;
41219  }
41220 
41221  if (face_element_added)
41222  {
41223  // Add the left-hand node to the set:
41224  // Boundary coordinate
41225  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
41226  vertex_coord[0] = bound_left[0];
41227 
41228  // Actual coordinates
41229  for(unsigned i=0;i<2;i++)
41230  {
41231  vertex_coord[i+1] = left_node_pt->x(i);
41232  }
41233  local_vertex_nodes.insert(vertex_coord);
41234 
41235  // Add the right-hand nodes to the set:
41236  // Boundary coordinate
41237  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
41238  vertex_coord[0] = bound_right[0];
41239 
41240  // Actual coordinates
41241  for(unsigned i=0;i<2;i++)
41242  {
41243  vertex_coord[i+1] = right_node_pt->x(i);
41244  }
41245  local_vertex_nodes.insert(vertex_coord);
41246 
41247  // Mark as done only if one of its nodes has been
41248  // added to the list
41249  face_element_done[ele_face_pt] = true;
41250  nsorted_face_elements++;
41251 
41252  break;
41253  }
41254 
41255  } // if (!edge_done[edge])
41256  } // for (iiedge < nedges)
41257  }while(face_element_added &&
41258  (nsorted_face_elements < nnon_halo_face_element));
41259 
41260  // -----------------------------------------------------------------
41261  // At this point we already have a sorted set of nodes and
41262  // can be used to peform the unrefinement and refinement procedures
41263  // -----------------------------------------------------------------
41264 
41265  // Get the number of nodes on the list
41266  const unsigned nlocal_nodes = local_vertex_nodes.size();
41267  // Change representation to vector for easy of handling ...
41268  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41269 
41270  // Copy the vertices of the nodes
41271  unsigned counter = 0;
41272  std::set<Vector<double> >::iterator it_vertex;
41273  for (it_vertex = local_vertex_nodes.begin();
41274  it_vertex != local_vertex_nodes.end();
41275  it_vertex++)
41276  {
41277  local_tmp_vector_vertex_node[counter].resize(3);
41278  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41279  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41280  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41281  counter++;
41282  }
41283 
41284  // *********************************************************************
41285  // 3) Create the vertices along the boundary using the target area to
41286  // define the distance among them
41287  // *********************************************************************
41288 
41289  // Clear the local containter to recover the nodes ordered using the
41290  // zeta value
41291  local_vertex_nodes.clear();
41292 
41293  // At the end of each unrefinement/refinement step store the new nodes
41294  // on the set that will give rise to the vertices of the new polyline
41295  // representation
41296  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41297  for (unsigned i = 0; i < nnew_nodes; i++)
41298  {
41299  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41300  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41301  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41302  vertex_nodes.insert(vertex_coord); // Global container
41303  local_vertex_nodes.insert(vertex_coord);
41304  }
41305 
41306 #ifdef OOMPH_HAS_MPI
41307  if (this->is_mesh_distributed())
41308  {
41309  // Add the set of vertices for the boundary, this will help to detect
41310  // if we need to deal with sub_boundaries and sub_polylines represen.
41311  sub_vertex_nodes.push_back(local_vertex_nodes);
41312  // Increase the counter for sub_boundaries
41313  nsub_boundaries++;
41314  }
41315 #endif
41316 
41317  } // while(nsorted_face_elements < nnon_halo_face_element)
41318 
41319  // Now turn into vector for ease of handling...
41320  unsigned npoly_vertex = vertex_nodes.size();
41321  tmp_vector_vertex_node.resize(npoly_vertex);
41322  unsigned count = 0;
41323  std::set<Vector<double> >::iterator it;
41324  for(it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
41325  {
41326  tmp_vector_vertex_node[count].resize(3);
41327  tmp_vector_vertex_node[count][0] = (*it)[0];
41328  tmp_vector_vertex_node[count][1] = (*it)[1];
41329  tmp_vector_vertex_node[count][2] = (*it)[2];
41330  ++count;
41331  }
41332 
41333 #ifdef OOMPH_HAS_MPI
41334  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41335 #ifdef PARANOID
41336  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41337  if (nsub_boundaries_set != nsub_boundaries)
41338  {
41339  std::ostringstream error_message;
41340  error_message
41341  << "The number of found sub-boundaries and the number of counted\n"
41342  << "sub-boundaries are different:\n"
41343  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
41344  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
41345  throw OomphLibError(error_message.str(),
41346  "RefineableTriangleMesh::update_polygon_after_restart()",
41347  OOMPH_EXCEPTION_LOCATION);
41348  }
41349 #endif
41350 
41351  // Verify if need to deal with sub_boundaries
41352  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41353  {
41354  // Mark the boundary as been splitted in the partition process
41355  this->Boundary_was_splitted[bound] = true;
41356  // Resize the vector to store the info. of sub-boundaries
41357  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41358  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41359  {
41360  // Turn info. into vector for ease of handling...
41361  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41362  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41363  unsigned subcount = 0;
41364  std::set<Vector<double> >::iterator subit;
41365  for(subit = sub_vertex_nodes[isub].begin();
41366  subit != sub_vertex_nodes[isub].end(); ++subit)
41367  {
41368  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41369  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41370  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41371  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41372  ++subcount;
41373  }
41374  }
41375  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41376  // --------- Stuff for the sub_boundaries ----- End section ------------
41377 #endif // OOMPH_HAS_MPI
41378 
41379 
41380  // For further processing the three-dimensional vector
41381  // has to be reduced to a two-dimensional vector
41382  unsigned n_vertex=tmp_vector_vertex_node.size();
41383 
41384  // Resize the vector for vectices
41385  vector_vertex_node.resize(n_vertex);
41386  for(unsigned i=0;i<n_vertex;i++)
41387  {
41388  vector_vertex_node[i].resize(2);
41389  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
41390  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
41391  }
41392 
41393 #ifdef OOMPH_HAS_MPI
41394  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41395  // Verify if need to deal with sub_boundaries
41396  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41397  {
41398  // For further processing the three-dimensional vector
41399  // has to be reduced to a two-dimensional vector
41400  // Resize the vector to store the info. of sub-boundaries
41401  sub_vector_vertex_node.resize(nsub_boundaries);
41402  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41403  {
41404  const unsigned subn_vertex =
41405  sub_tmp_vector_vertex_node[isub].size();
41406  // Resize the vector for vectices
41407  sub_vector_vertex_node[isub].resize(subn_vertex);
41408  for(unsigned i=0;i<subn_vertex;i++)
41409  {
41410  sub_vector_vertex_node[isub][i].resize(2);
41411  sub_vector_vertex_node[isub][i][0]=
41412  sub_tmp_vector_vertex_node[isub][i][1];
41413  sub_vector_vertex_node[isub][i][1]=
41414  sub_tmp_vector_vertex_node[isub][i][2];
41415  }
41416  }
41417  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41418 
41419  // We already have the info. for the sub-boundaries (if necessary)
41420  // and then we can create the sub-boundaries representations to
41421  // ease the generation of the mesh by Triangle
41422 
41423  // --------- Stuff for the sub_boundaries ----- End section ------------
41424 #endif // OOMPH_HAS_MPI
41425 
41426  // *********************************************************************
41427  // 4) Check for contiguousness
41428  // *********************************************************************
41429 #ifdef OOMPH_HAS_MPI
41430  // Only perform this checking if the mesh is not distributed
41431  // When the mesh is distributed the polylines continuity is
41432  // addressed with the sort_polylines_helper() method
41433  if (!this->is_mesh_distributed())
41434 #endif
41435  {
41436  if ( p > 0 )
41437  {
41438  //Final end point of previous line
41439  Vector<double> final_vertex_of_previous_segment;
41440  unsigned n_prev_vertex =
41441  polygon_pt->curve_section_pt(p-1)->nvertex();
41442  final_vertex_of_previous_segment =
41443  polygon_pt->polyline_pt(p-1)->
41444  vertex_coordinate(n_prev_vertex-1);
41445 
41446  unsigned prev_seg_boundary_id =
41447  polygon_pt->curve_section_pt(p-1)->boundary_id();
41448 
41449  //Find the error between the final vertex of the previous
41450  //line and the first vertex of the current line
41451  double error = 0.0;
41452  for(unsigned i=0;i<2;i++)
41453  {
41454  const double dist =
41455  final_vertex_of_previous_segment[i] -
41456  (*vector_vertex_node.begin())[i];
41457  error += dist*dist;
41458  }
41459  error = sqrt(error);
41460 
41461  //If the error is bigger than the tolerance then
41462  //we probably need to reverse, but better check
41463  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41464  {
41465  //Find the error between the final vertex of the previous
41466  //line and the last vertex of the current line
41467  double rev_error = 0.0;
41468  for(unsigned i=0;i<2;i++)
41469  {
41470  const double dist =
41471  final_vertex_of_previous_segment[i] -
41472  (*--vector_vertex_node.end())[i];
41473  rev_error += dist*dist;
41474  }
41475  rev_error = sqrt(rev_error);
41476 
41477  if(rev_error >
41478  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41479  {
41480  // It could be possible that the first segment be reversed and we
41481  // did not notice it because this check does not apply for the
41482  // first segment. We can verify if the first segment is reversed
41483  // by using the vertex number 1
41484  if (p == 1)
41485  {
41486  //Initial end point of previous line
41487  Vector<double> initial_vertex_of_previous_segment;
41488 
41489  initial_vertex_of_previous_segment =
41490  polygon_pt->polyline_pt(p-1)->
41491  vertex_coordinate(0);
41492 
41493  unsigned prev_seg_boundary_id =
41494  polygon_pt->curve_section_pt(p-1)->boundary_id();
41495 
41496  //Find the error between the initial vertex of the previous
41497  //line and the first vertex of the current line
41498  double error = 0.0;
41499  for(unsigned i=0;i<2;i++)
41500  {
41501  const double dist =
41502  initial_vertex_of_previous_segment[i] -
41503  (*vector_vertex_node.begin())[i];
41504  error += dist*dist;
41505  }
41506  error = sqrt(error); // Reversed only the previous one
41507 
41508  //If the error is bigger than the tolerance then
41509  //we probably need to reverse, but better check
41510  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41511  {
41512  //Find the error between the final vertex of the previous
41513  //line and the last vertex of the current line
41514  double rev_error = 0.0;
41515  for(unsigned i=0;i<2;i++)
41516  {
41517  const double dist =
41518  initial_vertex_of_previous_segment[i] -
41519  (*--vector_vertex_node.end())[i];
41520  rev_error += dist*dist;
41521  }
41522  rev_error = sqrt(rev_error); // Reversed both the current one and
41523  // the previous one
41524 
41525  if (rev_error >
41526  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41527  {
41528  std::ostringstream error_stream;
41529  error_stream
41530  <<"The distance between the first node of the current\n"
41531  <<"line segment (boundary " << bound << ") and either end of "
41532  << "the previous line segment\n"
41533  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
41534  << "the desired tolerance " <<
41535  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
41536  << "This suggests that the polylines defining the polygonal\n"
41537  << "representation are not properly ordered.\n"
41538  << "Fail on last vertex of polyline: ("
41539  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
41540  << bound << ").\nThis should have failed when first trying to"
41541  << " construct the\npolygon.\n";
41542  throw OomphLibError(error_stream.str(),
41543  "RefineableTriangleMesh::update_polygon_after_restart()",
41544  OOMPH_EXCEPTION_LOCATION);
41545  }
41546  else
41547  {
41548  // Reverse both
41549  // Reverse the current vector to line up with the previous one
41550  std::reverse(vector_vertex_node.begin(),
41551  vector_vertex_node.end());
41552  polygon_pt->polyline_pt(p-1)->reverse();
41553  }
41554  }
41555  else
41556  {
41557  // Reverse the previous one
41558  polygon_pt->polyline_pt(p-1)->reverse();
41559  }
41560 
41561  } // if p == 1
41562  else
41563  {
41564  std::ostringstream error_stream;
41565  error_stream
41566  <<"The distance between the first node of the current\n"
41567  <<"line segment (boundary " << bound << ") and either end of "
41568  <<"the previous line segment\n"
41569  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
41570  <<"desired tolerance " <<
41571  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
41572  <<"This suggests that the polylines defining the polygonal\n"
41573  <<"representation are not properly ordered.\n"
41574  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
41575  << ") and\nfirst vertex of polyline (" << bound << ").\n"
41576  << "This should have failed when first trying to construct the\n"
41577  << "polygon.\n";
41578  throw OomphLibError(
41579  error_stream.str(),
41580  "RefineableTriangleMesh::update_polygon_after_restart()",
41581  OOMPH_EXCEPTION_LOCATION);
41582  }
41583  }
41584  else
41585  {
41586  //Reverse the current vector to line up with the previous one
41587  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
41588  }
41589  } // error
41590  } // p > 0
41591  } // is mesh not distributed
41592 
41593  // *********************************************************************
41594  // 5) Update the polylines representation
41595  // *********************************************************************
41596  // if (applied_area_length_constraint)
41597  // If only applied when there is a change then it keeps the
41598  // previous polyline representation, it means, it does not delete
41599  // the boundaries that are not part of the domain. We must update
41600  // the boundary representation
41601  {
41602  n_vertex = vector_vertex_node.size();
41603 
41604  // Now update the polyline according to the new vertices
41605  // The new one representation
41606  TriangleMeshPolyLine *tmp_polyline_pt =
41607  new TriangleMeshPolyLine(vector_vertex_node,bound);
41608 
41609  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41610  // {
41611  // DEBP(h);
41612  // DEBP(vector_vertex_node[h][0]);
41613  // DEBP(vector_vertex_node[h][1]);
41614  // }
41615 
41616  // Create a temporal "curve section" version of the recently created
41617  // polyline
41618  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
41619 
41620  // Tolerance below which the middle point can be deleted
41621  // (ratio of deflection to element length)
41622  double unrefinement_tolerance=
41623  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41624 
41625  // Tolerance to add points
41626  double refinement_tolerance=
41627  polygon_pt->polyline_pt(p)->refinement_tolerance();
41628 
41629  // Establish refinement and unrefinement tolerance
41630  tmp_polyline_pt->set_unrefinement_tolerance(
41631  unrefinement_tolerance);
41632  tmp_polyline_pt->set_refinement_tolerance(
41633  refinement_tolerance);
41634 
41635  // Establish the maximum length constraint
41636  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41637  tmp_polyline_pt->set_maximum_length(maximum_length);
41638 
41639  if (n_vertex >= 2)
41640  {
41641  // Pass the connection information from the old polyline to the
41642  // new one
41643  this->copy_connection_information(polygon_pt->polyline_pt(p),
41644  tmp_curve_section_pt);
41645  }
41646 
41647  //Now update the polyline according to the new vertices but
41648  //first check if the object is allowed to delete the representation
41649  //or if it should be done by other object
41650  bool delete_it_on_destructor = false;
41651 
41652  std::set<TriangleMeshCurveSection*>::iterator it =
41653  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41654 
41655  if (it!=this->Free_curve_section_pt.end())
41656  {
41657  this->Free_curve_section_pt.erase(it);
41658  delete polygon_pt->curve_section_pt(p);
41659  delete_it_on_destructor = true;
41660  }
41661 
41662  // *****************************************************************
41663  // Copying the new representation
41664  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41665 
41666  // Update the Boundary - Polyline map
41667  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
41668 
41669  if (delete_it_on_destructor)
41670  {
41671  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41672  }
41673 
41674 #ifdef OOMPH_HAS_MPI
41675  // --------- Stuff for the sub_boundaries ----- Begin section --------
41676  // Verify if need to deal with sub_boundaries
41677  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41678  {
41679  // Create temporary representations for the boundaries, only to
41680  // create the mesh when calling Triangle
41681  // Clear all previous stored data
41682  this->Boundary_subpolylines[bound].clear();
41683  // Now create storage for the sub-boundaries
41684  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41685  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41686  {
41687  // Now update the polyline according to the sub set of
41688  // vertices, set the chunk number of the polyline
41689  TriangleMeshPolyLine *sub_tmp_polyline_pt =
41690  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
41691 
41692  // Add the sub-polyline to the container to represent the boundary
41693  // in parts
41694  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
41695 
41696  // No need to send the unrefinement/refinement and maximum
41697  // length constraints since these are only temporary
41698  // representations. These polylines can be deleted once the
41699  // new polygons that represent the distributed domain have
41700  // been created
41701 
41702  } // for (isub < nsub_boundaries)
41703 
41704  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41705  // --------- Stuff for the sub_boundaries ----- End section ---------
41706 #endif // OOMPH_HAS_MPI
41707 
41708  } // update polyline representation
41709 
41710  // Delete the allocated memory for the geometric object that
41711  // represents the curvilinear boundary
41712  delete mesh_geom_obj_pt;
41713 
41714  } // npolyline
41715 
41716  // Cleanup the face mesh
41717  for(unsigned p=0;p<n_polyline;p++)
41718  {
41719  face_mesh_pt[p]->flush_node_storage();
41720  delete face_mesh_pt[p];
41721  }
41722 
41723 }
41724 
41725 
41726 //======================================================================
41727 /// \short Updates the open curve representation after restart
41728 //======================================================================
41729 template <class ELEMENT>
41731 update_open_curve_after_restart(TriangleMeshOpenCurve* &open_curve_pt)
41732 {
41733  // **********************************************************************
41734  // 1) Get the vertices along the boundaries ids of the polylines and
41735  // update them
41736  // **********************************************************************
41737 
41738  // (1.1) Get the face mesh representation
41739  Vector<Mesh*> face_mesh_pt;
41740  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
41741 
41742  // (1.2) Create vertices of the polylines by using the vertices of the
41743  // FaceElements
41744  Vector<double> vertex_coord(3); // zeta,x,y
41745  Vector<double> bound_left(1);
41746  Vector<double> bound_right(1);
41747 
41748  const unsigned ncurve_section = open_curve_pt->ncurve_section();
41749  // Go for each curve section
41750  for(unsigned cs = 0; cs < ncurve_section; cs++)
41751  {
41752  // Get the MeshAsGeomObject representation just once per polyline,
41753  // this object is only used by the
41754  // refine_boundary_constrained_by_target_area() method. We get it here
41755  // to ensure that all processors (in a distributed context) get this
41756  // representation just once, and because an AllToAll MPI communication
41757  // is used in this calling
41758  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
41759 
41760  //Get the boundary id
41761  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
41762 
41763  /// Use a vector of vector for vertices and target areas to deal
41764  /// with the cases when the boundaries are split bn the
41765  /// distribution process. Internal boundaries may be completely or
41766  /// partially overlapped by shared boundaries
41767 
41768  // Loop over the face elements and add their vertices (they are
41769  // automatically sorted because of the set)
41770  const unsigned nface_element = face_mesh_pt[cs]->nelement();
41771  // Store the non halo elements and the element at the other side of
41772  // the boundary (whatever it be halo or not), the first will be the
41773  // ones from which we will get the vertices (in even position)
41774  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
41775 
41776  // Map to store the index of the face element on a boundary
41777  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41778 
41779  // Map to know the already sorted face elements
41780  std::map<FiniteElement*,bool> face_element_done;
41781 
41782  for(unsigned ef = 0; ef < nface_element; ++ef)
41783  {
41784  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
41785 
41786  // Skip the halo elements (not used as base elements, only
41787  // include those elements which one of its counterparts -- at the
41788  // other side of the boundary -- is non halo)
41789 #ifdef OOMPH_HAS_MPI
41790  if (this->is_mesh_distributed())
41791  {
41792  // Only work with non-halo elements
41793  if (ele_face_pt->is_halo()) {continue;}
41794  }
41795 #endif
41796 
41797  // Check if not already done
41798  if (!face_element_done[ele_face_pt])
41799  {
41800  // Add the element and look for the element at the other side
41801  // of the boundary to add it immediately after the new added
41802  // element
41803  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
41804  // Create the map of the face element with the index
41805  face_element_index_on_boundary[ele_face_pt] = ef;
41806  // Mark the current element as done
41807  face_element_done[ele_face_pt] = true;
41808  // Get the number of nodes
41809  const unsigned nnodes = ele_face_pt->nnode();
41810  // Get the left and right node to look for the elements at the
41811  // other side of the boundary
41812  Node* left_node_pt = ele_face_pt->node_pt(0);
41813  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
41814 
41815 #ifdef PARANOID
41816  // Flag to know if the element at the other side of the
41817  // boundary was found
41818  bool found_other_side_face_ele = false;
41819 #endif
41820  for (unsigned iface = 0; iface < nface_element; iface++)
41821  {
41822  // Get the candidate face element
41823  FiniteElement *cele_face_pt =
41824  face_mesh_pt[cs]->finite_element_pt(iface);
41825  // Check if not already done
41826  if (!face_element_done[cele_face_pt])
41827  {
41828  Node* cleft_node_pt = cele_face_pt->node_pt(0);
41829  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
41830 
41831  // Check if the nodes are the same
41832  if ((left_node_pt == cleft_node_pt &&
41833  right_node_pt == cright_node_pt) ||
41834  (left_node_pt == cright_node_pt &&
41835  right_node_pt == cleft_node_pt))
41836  {
41837  // Add the element to the storage
41838  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
41839  // ... and mark the element as done
41840  face_element_done[cele_face_pt] = true;
41841  // Create the map of the face element with the index
41842  face_element_index_on_boundary[cele_face_pt] = iface;
41843 #ifdef PARANOID
41844  // Set the flag of found other side face element
41845  found_other_side_face_ele = true;
41846 #endif
41847  break;
41848  }
41849  }
41850  } // (iface < nface_element)
41851 
41852 #ifdef PARANOID
41853  if (!found_other_side_face_ele)
41854  {
41855  std::ostringstream error_message;
41856  error_message
41857  << "The face element at the other side of the boundary ("
41858  << bound << ") was not found!!\n"
41859  << "These are the nodes of the face element:\n"
41860  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
41861  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
41862  throw OomphLibError(error_message.str(),
41863  "RefineableTriangleMesh::update_open_curve_after_restart()",
41864  OOMPH_EXCEPTION_LOCATION);
41865  }
41866 #endif
41867  } // if (!face_ele_done[ele_face_pt])
41868 
41869  } // (ef < nface_element)
41870 
41871  // Clear the map of the already done face elements
41872  // This will now be used to sort the face elements
41873  face_element_done.clear();
41874 
41875  // Set of coordinates that are on the boundary
41876  // The entries are sorted on first entry in vector which stores
41877  // the boundary coordinate so the vertices come out in order!
41878  std::set<Vector<double> > vertex_nodes;
41879 
41880  // Vector to store the vertices, transfer the sorted vertices from the
41881  // set to this vector, --- including the z-value ---
41882  Vector<Vector<double> > tmp_vector_vertex_node;
41883 
41884  // Vector to store the coordinates of the polylines, same as the
41885  // tmp_vector_vertex_node vector (after adding more nodes) but
41886  // --- without the z-value ---, used to re-generate the polylines
41887  Vector<Vector<double> > vector_vertex_node;
41888 
41889 #ifdef OOMPH_HAS_MPI
41890  // Indicates if the set of vertices give rise to a internal
41891  // boundary that will be used as shared boundary or as normal
41892  // internal boundary -- Only used to deal with internal boundaries
41893  // in a distributed scheme
41894  std::vector<bool> internal_to_shared_boundary;
41895 
41896  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41897  // Set of coordinates that are on the boundary (splitted boundary version)
41898  // The first vector is used to allocate the points for each sub-boundary
41899  // Set entries are ordered on first entry in vector which stores
41900  // the boundary coordinate so the vertices come out in order!
41901  Vector<std::set<Vector<double> > > sub_vertex_nodes;
41902 
41903  // Vector to store the vertices, transfer the sorted vertices from the
41904  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41905  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
41906 
41907  // Vector to store the coordinates of the polylines that will represent
41908  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41909  // but --- without the z-value ---, used to generate the sub-polylines
41910  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41911 
41912  // --------- Stuff to deal with splitted boundaries ----------- End ------
41913 #endif
41914 
41915  // Sort face elements, separate those with both nonhalo face
41916  // elements from those with one halo and one nonhalo face element
41917 
41918  // Number of done face elements
41919  unsigned nsorted_face_elements = 0;
41920 
41921 #ifdef OOMPH_HAS_MPI
41922  // Counter for sub_boundaries
41923  unsigned nsub_boundaries = 0;
41924 #endif // #ifdef OOMPH_HAS_MPI
41925 
41926  // Total number of non halo double face element
41927  const unsigned nnon_halo_doubled_face_ele =
41928  non_halo_doubled_face_element_pt.size();
41929 
41930  // Continue until all the face elements have been sorted
41931  // This while is to deal with the cases of splitted boundaries
41932  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
41933  {
41934  // Get and initial face element
41935  FiniteElement* ele_face_pt = 0;
41936  FiniteElement* repeated_ele_face_pt = 0;
41937 #ifdef PARANOID
41938  bool found_initial_face_element = false;
41939 #endif
41940 
41941  // Flag to know if we are working with a face element which the
41942  // face element at the other side of the boundary is also non
41943  // halo
41944  bool both_root_face_elements_are_nonhalo = false;
41945 
41946  unsigned iface = 0;
41947  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
41948  {
41949  ele_face_pt = non_halo_doubled_face_element_pt[iface];
41950  // If not done then take it as initial face element
41951  if (!face_element_done[ele_face_pt])
41952  {
41953  // Mark it as done
41954  face_element_done[ele_face_pt] = true;
41955  // Get the other side boundary face element
41956  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
41957  // ... also mark as done the repeated face element
41958  face_element_done[repeated_ele_face_pt] = true;
41959 
41960 #ifdef OOMPH_HAS_MPI
41961  if (!repeated_ele_face_pt->is_halo())
41962  {both_root_face_elements_are_nonhalo = true;}
41963 #endif // #ifdef OOMPH_HAS_MPI
41964 
41965  // Plus two because internal boundaries have
41966  // two face elements per each edge
41967  nsorted_face_elements+=2;
41968  iface+=2;
41969 #ifdef PARANOID
41970  // And set the flag to true
41971  found_initial_face_element = true;
41972 #endif
41973  break;
41974  }
41975  }
41976 
41977 #ifdef PARANOID
41978  if (!found_initial_face_element)
41979  {
41980  std::ostringstream error_message;
41981  error_message
41982  <<"Could not find an initial face element for the current segment\n";
41983  // << "----- Possible memory leak -----\n";
41984  throw OomphLibError(error_message.str(),
41985  OOMPH_CURRENT_FUNCTION,
41986  OOMPH_EXCEPTION_LOCATION);
41987  }
41988 #endif
41989 
41990  // Local set of coordinates that are on the boundary Set entries
41991  // are ordered on first entry in vector which stores the boundary
41992  // coordinate so the vertices come out in order
41993  std::set<Vector<double> > local_vertex_nodes;
41994 
41995  // Vector to store the vertices, transfer the sorted vertices from the
41996  // set (local) to this vector (local), --- including the z-value ---
41997  Vector<Vector<double> > local_tmp_vector_vertex_node;
41998 
41999  // ------------------------------------------------------------------
42000  // ------------------------------------------------------------------
42001  // Add the vertices of the initial face element to the set of local
42002  // sorted vertices
42003  // ------------------------------------------------------------------
42004  // ------------------------------------------------------------------
42005  const unsigned nnode = ele_face_pt->nnode();
42006  // Add the left-hand node to the set:
42007  // Boundary coordinate
42008  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
42009  vertex_coord[0] = bound_left[0];
42010 
42011  // Actual coordinates
42012  for(unsigned i=0;i<2;i++)
42013  {
42014  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
42015  }
42016  local_vertex_nodes.insert(vertex_coord);
42017 
42018  // Add the right-hand node to the set:
42019  // Boundary coordinate
42020  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
42021  bound_right);
42022  vertex_coord[0] = bound_right[0];
42023 
42024  // Actual coordinates
42025  for(unsigned i=0;i<2;i++)
42026  {
42027  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
42028  }
42029  local_vertex_nodes.insert(vertex_coord);
42030 
42031  // The initial and final node on the set
42032  Node *first_node_pt = ele_face_pt->node_pt(0);
42033  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
42034 
42035  // Continue iterating if a new face element has been added to the
42036  // list
42037  bool face_element_added = false;
42038 
42039  // While a new face element has been added to the set of sorted
42040  // face elements then re-iterate
42041  do
42042  {
42043  // Start from the next face elements since we have already
42044  // added the previous one as the initial face element (any
42045  // previous face element had to be added on previous
42046  // iterations)
42047  for (unsigned iiface=iface;
42048  iiface<nnon_halo_doubled_face_ele;iiface+=2)
42049  {
42050  face_element_added = false;
42051  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42052 
42053  // Check that the face element with which we are working has
42054  // the same conditions as the root face element (both faces
42055  // are nonhalo or one face is halo and the other nonhalo)
42056 
42057  // Get the face element at the other side of the boundary
42058  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42059  bool both_face_elements_are_nonhalo = false;
42060 
42061 #ifdef OOMPH_HAS_MPI
42062  if (!repeated_ele_face_pt->is_halo())
42063  {both_face_elements_are_nonhalo = true;}
42064 #endif // #ifdef OOMPH_HAS_MPI
42065 
42066  if (!face_element_done[ele_face_pt] &&
42067  (both_face_elements_are_nonhalo ==
42068  both_root_face_elements_are_nonhalo))
42069  {
42070  // Get each individual node to check if they are contiguous
42071  const unsigned nlnode = ele_face_pt->nnode();
42072  Node* left_node_pt = ele_face_pt->node_pt(0);
42073  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
42074 
42075  if (left_node_pt == first_node_pt)
42076  {
42077  first_node_pt = right_node_pt;
42078  face_element_added = true;
42079  }
42080  else if (left_node_pt == last_node_pt)
42081  {
42082  last_node_pt = right_node_pt;
42083  face_element_added = true;
42084  }
42085  else if (right_node_pt == first_node_pt)
42086  {
42087  first_node_pt = left_node_pt;
42088  face_element_added = true;
42089  }
42090  else if (right_node_pt == last_node_pt)
42091  {
42092  last_node_pt = left_node_pt;
42093  face_element_added = true;
42094  }
42095 
42096  if (face_element_added)
42097  {
42098  // Add the left-hand node to the set:
42099  // Boundary coordinate
42100  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
42101  vertex_coord[0] = bound_left[0];
42102 
42103  // Actual coordinates
42104  for(unsigned i=0;i<2;i++)
42105  {
42106  vertex_coord[i+1] = left_node_pt->x(i);
42107  }
42108  local_vertex_nodes.insert(vertex_coord);
42109 
42110  // Add the right-hand nodes to the set:
42111  // Boundary coordinate
42112  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
42113  vertex_coord[0] = bound_right[0];
42114 
42115  // Actual coordinates
42116  for(unsigned i=0;i<2;i++)
42117  {
42118  vertex_coord[i+1] = right_node_pt->x(i);
42119  }
42120  local_vertex_nodes.insert(vertex_coord);
42121 
42122  // Mark as done only if one of its nodes has been
42123  // added to the list
42124  face_element_done[ele_face_pt] = true;
42125  // .. also mark as done the face element at the othe side of
42126  // the boundary
42127  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42128  face_element_done[repeated_ele_face_pt] = true;
42129  // ... and increase the number of sorted face elements
42130  nsorted_face_elements+=2;
42131 
42132  break;
42133  }
42134 
42135  } // if (!face_element_done[[ele_face_pt])
42136  } // for (iiface<nnon_halo_doubled_face_ele)
42137  }while(face_element_added &&
42138  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42139 
42140  // -------------------------------------------------------------
42141  // At this point we already have a sorted set of nodes and can
42142  // be used to peform the unrefinement and refinement procedures
42143  // -------------------------------------------------------------
42144 
42145  // Get the number of nodes on the list
42146  const unsigned nlocal_nodes = local_vertex_nodes.size();
42147  // Change representation to vector for easy of handling ...
42148  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42149 
42150  // Copy the vertices of the nodes
42151  unsigned counter = 0;
42152  std::set<Vector<double> >::iterator it_vertex;
42153  for (it_vertex = local_vertex_nodes.begin();
42154  it_vertex != local_vertex_nodes.end();
42155  it_vertex++)
42156  {
42157  local_tmp_vector_vertex_node[counter].resize(3);
42158  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42159  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42160  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42161  counter++;
42162  }
42163 
42164  // The unrefinement and refinement process needs to be applied
42165  // from the bottom-left node since the internal open curve could
42166  // lie on the shared boundaries
42167  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
42168  local_tmp_vector_vertex_node[0][2])
42169  {
42170  std::reverse(local_tmp_vector_vertex_node.begin(),
42171  local_tmp_vector_vertex_node.end());
42172  }
42173  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
42174  local_tmp_vector_vertex_node[0][2])
42175  {
42176  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
42177  local_tmp_vector_vertex_node[0][1])
42178  {
42179  std::reverse(local_tmp_vector_vertex_node.begin(),
42180  local_tmp_vector_vertex_node.end());
42181  }
42182  }
42183 
42184  // ****************************************************************
42185  // 3) Create the vertices along the boundary using the target
42186  // area to define the distance among them
42187  // ****************************************************************
42188 
42189  // Clear the local containter to recover the nodes ordered using
42190  // the zeta value
42191  local_vertex_nodes.clear();
42192 
42193  // At the end of each unrefinement/refinement step store the new
42194  // nodes on the set that will give rise to the vertices of the
42195  // new polyline representation
42196  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42197  for (unsigned i = 0; i < nnew_nodes; i++)
42198  {
42199  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42200  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42201  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42202  vertex_nodes.insert(vertex_coord); // Global container
42203  local_vertex_nodes.insert(vertex_coord);
42204  }
42205 
42206 #ifdef OOMPH_HAS_MPI
42207  if (this->is_mesh_distributed())
42208  {
42209  // Add the set of vertices for the boundary, this will help to
42210  // detect if we need to deal with sub_boundaries and
42211  // sub_polylines representations
42212  sub_vertex_nodes.push_back(local_vertex_nodes);
42213  // Increase the counter for sub_boundaries
42214  nsub_boundaries++;
42215 
42216  // Mark if the polyline created by these vertices will be used
42217  // as a shared boundary or as an internal boundary
42218  if (both_root_face_elements_are_nonhalo)
42219  {internal_to_shared_boundary.push_back(false);}
42220  else
42221  {internal_to_shared_boundary.push_back(true);}
42222  }
42223 #endif
42224 
42225  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42226  // This while is in charge of sorting all the face elements to
42227  // create the new representation of the polyline (also deals
42228  // with the sub-boundary cases)
42229 
42230  // Now turn into vector for ease of handling...
42231  const unsigned npoly_vertex = vertex_nodes.size();
42232  tmp_vector_vertex_node.resize(npoly_vertex);
42233  unsigned count = 0;
42234  std::set<Vector<double> >::iterator it;
42235  for (it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
42236  {
42237  tmp_vector_vertex_node[count].resize(3);
42238  tmp_vector_vertex_node[count][0] = (*it)[0];
42239  tmp_vector_vertex_node[count][1] = (*it)[1];
42240  tmp_vector_vertex_node[count][2] = (*it)[2];
42241  ++count;
42242  }
42243 
42244 #ifdef OOMPH_HAS_MPI
42245  // Check that the number of set of vertices marked to be shared or
42246  // internal boundaries be the same as the total number of
42247  // sub-boundaries
42248 #ifdef PARANOID
42249  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42250  const unsigned ninternal_to_shared_boundaries =
42251  internal_to_shared_boundary.size();
42252  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42253  {
42254  std::ostringstream error_message;
42255  error_message
42256  << "The number of found sub-boundaries and the number of marked "
42257  << "internal\nboundaries are different\n"
42258  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42259  << "Number of marked internal boundaries: ("
42260  << ninternal_to_shared_boundaries << ")\n\n";
42261  throw OomphLibError(error_message.str(),
42262  "RefineableTriangleMesh::update_open_curve_after_restart()",
42263  OOMPH_EXCEPTION_LOCATION);
42264  }
42265 #endif
42266 
42267  // --------- Stuff for the sub_boundaries ----- Begin section -------
42268 #ifdef PARANOID
42269  if (nsub_boundaries_set != nsub_boundaries)
42270  {
42271  std::ostringstream error_message;
42272  error_message
42273  << "The number of found sub-boundaries and the number of counted\n"
42274  << "sub-boundaries are different:\n"
42275  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42276  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
42277  throw OomphLibError(error_message.str(),
42278  "RefineableTriangleMesh::update_open_curve_after_restart()",
42279  OOMPH_EXCEPTION_LOCATION);
42280  }
42281 #endif
42282 
42283  // Verify if need to deal with sub_boundaries
42284  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42285  {
42286  // Mark the boundary as been splitted in the partition process
42287  this->Boundary_was_splitted[bound] = true;
42288  // Resize the vector to store the info. of sub-boundaries
42289  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42290  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42291  {
42292  // Turn info. into vector for ease of handling...
42293  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42294  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42295  unsigned subcount = 0;
42296  std::set<Vector<double> >::iterator subit;
42297  for(subit = sub_vertex_nodes[isub].begin();
42298  subit != sub_vertex_nodes[isub].end(); ++subit)
42299  {
42300  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42301  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42302  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42303  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42304  ++subcount;
42305  }
42306  }
42307  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42308  // --------- Stuff for the sub_boundaries ----- End section ----------
42309 #endif // OOMPH_HAS_MPI
42310 
42311  // For further processing the three-dimensional vector has to be
42312  // reduced to a two-dimensional vector
42313  unsigned n_vertex=tmp_vector_vertex_node.size();
42314 
42315  // Resize the vector for vectices
42316  vector_vertex_node.resize(n_vertex);
42317  for(unsigned i=0;i<n_vertex;i++)
42318  {
42319  vector_vertex_node[i].resize(2);
42320  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
42321  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
42322  }
42323 
42324 #ifdef OOMPH_HAS_MPI
42325  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42326  // Verify if need to deal with sub_boundaries
42327  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42328  {
42329  // For further processing the three-dimensional vector
42330  // has to be reduced to a two-dimensional vector
42331  // Resize the vector to store the info. of sub-boundaries
42332  sub_vector_vertex_node.resize(nsub_boundaries);
42333  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42334  {
42335  const unsigned subn_vertex =
42336  sub_tmp_vector_vertex_node[isub].size();
42337  // Resize the vector for vectices
42338  sub_vector_vertex_node[isub].resize(subn_vertex);
42339  for(unsigned i=0;i<subn_vertex;i++)
42340  {
42341  sub_vector_vertex_node[isub][i].resize(2);
42342  sub_vector_vertex_node[isub][i][0]=
42343  sub_tmp_vector_vertex_node[isub][i][1];
42344  sub_vector_vertex_node[isub][i][1]=
42345  sub_tmp_vector_vertex_node[isub][i][2];
42346  }
42347  }
42348  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42349 
42350  // We already have the info. for the sub-boundaries (if necessary) and
42351  // then we can create the sub-boundaries representations to ease the
42352  // generation of the mesh by Triangle
42353 
42354  // --------- Stuff for the sub_boundaries ----- End section ------------
42355 #endif // OOMPH_HAS_MPI
42356 
42357  // *********************************************************************
42358  // 4) Check for contiguousness
42359  // *********************************************************************
42360 #ifdef OOMPH_HAS_MPI
42361  // Only perform this checking if the mesh is not distributed
42362  // When the mesh is distributed the polylines continuity is
42363  // addressed with the sort_polylines_helper() method
42364  if (!this->is_mesh_distributed())
42365 #endif
42366  {
42367  if ( cs > 0 )
42368  {
42369  //Final end point of previous line
42370  Vector<double> final_vertex_of_previous_segment;
42371  unsigned n_prev_vertex =
42372  open_curve_pt->curve_section_pt(cs-1)->nvertex();
42373  final_vertex_of_previous_segment =
42374  open_curve_pt->polyline_pt(cs-1)->
42375  vertex_coordinate(n_prev_vertex-1);
42376 
42377  unsigned prev_seg_boundary_id =
42378  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42379 
42380  //Find the error between the final vertex of the previous
42381  //line and the first vertex of the current line
42382  double error = 0.0;
42383  for(unsigned i=0;i<2;i++)
42384  {
42385  const double dist =
42386  final_vertex_of_previous_segment[i] -
42387  (*vector_vertex_node.begin())[i];
42388  error += dist*dist;
42389  }
42390  error = sqrt(error);
42391 
42392  //If the error is bigger than the tolerance then
42393  //we probably need to reverse, but better check
42394  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42395  {
42396  //Find the error between the final vertex of the previous
42397  //line and the last vertex of the current line
42398  double rev_error = 0.0;
42399  for(unsigned i=0;i<2;i++)
42400  {
42401  const double dist =
42402  final_vertex_of_previous_segment[i] -
42403  (*--vector_vertex_node.end())[i];
42404  rev_error += dist*dist;
42405  }
42406  rev_error = sqrt(rev_error);
42407 
42408  if(rev_error >
42409  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42410  {
42411  // It could be possible that the first segment be reversed and we
42412  // did not notice it because this check does not apply for the
42413  // first segment. We can verify if the first segment is reversed
42414  // by using the vertex number 1
42415  if (cs == 1)
42416  {
42417  //Initial end point of previous line
42418  Vector<double> initial_vertex_of_previous_segment;
42419 
42420  initial_vertex_of_previous_segment =
42421  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
42422 
42423  unsigned prev_seg_boundary_id =
42424  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42425 
42426  //Find the error between the initial vertex of the previous
42427  //line and the first vertex of the current line
42428  double error = 0.0;
42429  for(unsigned i=0;i<2;i++)
42430  {
42431  const double dist =
42432  initial_vertex_of_previous_segment[i] -
42433  (*vector_vertex_node.begin())[i];
42434  error += dist*dist;
42435  }
42436  error = sqrt(error); // Reversed only the previous one
42437 
42438  //If the error is bigger than the tolerance then
42439  //we probably need to reverse, but better check
42440  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42441  {
42442  //Find the error between the final vertex of the previous
42443  //line and the last vertex of the current line
42444  double rev_error = 0.0;
42445  for(unsigned i=0;i<2;i++)
42446  {
42447  const double dist =
42448  initial_vertex_of_previous_segment[i] -
42449  (*--vector_vertex_node.end())[i];
42450  rev_error += dist*dist;
42451  }
42452  rev_error = sqrt(rev_error); // Reversed both the current
42453  // one and the previous one
42454 
42455  if (rev_error >
42456  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42457  {
42458  std::ostringstream error_stream;
42459  error_stream
42460  <<"The distance between the first node of the current\n"
42461  <<"line segment (boundary "<<bound<<") and either end of "
42462  <<"the previous line segment\n"
42463  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
42464  << " the desired tolerance " <<
42465  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
42466  <<"This suggests that the polylines defining the polygonal\n"
42467  <<"representation are not properly ordered.\n"
42468  <<"Fail on last vertex of polyline: ("
42469  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
42470  <<bound<< ").\nThis should have failed when first trying to "
42471  <<"construct the\npolygon.\n";
42472  throw OomphLibError(error_stream.str(),
42473  "RefineableTriangleMesh::update_open_curve_after_restart()",
42474  OOMPH_EXCEPTION_LOCATION);
42475  }
42476  else
42477  {
42478  // Reverse both
42479  // Reverse the current vector to line up with the previous one
42480  std::reverse(vector_vertex_node.begin(),
42481  vector_vertex_node.end());
42482  open_curve_pt->polyline_pt(cs-1)->reverse();
42483  }
42484  }
42485  else
42486  {
42487  // Reverse the previous one
42488  open_curve_pt->polyline_pt(cs-1)->reverse();
42489  }
42490 
42491  } // if (cs == 1)
42492  else
42493  {
42494  std::ostringstream error_stream;
42495  error_stream
42496  <<"The distance between the first node of the current\n"
42497  <<"line segment (boundary " << bound << ") and either end of "
42498  <<"the previous line segment\n"
42499  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
42500  <<"desired tolerance " <<
42501  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
42502  <<"This suggests that the polylines defining the polygonal\n"
42503  <<"representation are not properly ordered.\n"
42504  <<"Fail on last vertex of polyline: (" << prev_seg_boundary_id
42505  <<") and\nfirst vertex of polyline (" << bound << ").\n"
42506  <<"This should have failed when first trying to construct the\n"
42507  <<"polygon.\n";
42508  throw OomphLibError(
42509  error_stream.str(),
42510  "RefineableTriangleMesh::update_open_curve_after_restart()",
42511  OOMPH_EXCEPTION_LOCATION);
42512  }
42513  }
42514  else
42515  {
42516  //Reverse the current vector to line up with the previous one
42517  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
42518  }
42519  } // error
42520  } // (cs > 0)
42521  } // is mesh not distributed
42522 
42523  // DEBP(applied_area_length_constraint);
42524  // DEBP(p);
42525  // getchar();
42526  // *********************************************************************
42527  // 5) Update the polylines representation
42528  // *********************************************************************
42529  // if (applied_area_length_constraint)
42530  // If only applied when there is a change then it keeps the
42531  // previous polyline representation, it means, it does not delete
42532  // the boundaries that are not part of the domain. We must update
42533  // the boundary representation
42534  {
42535  n_vertex = vector_vertex_node.size();
42536 
42537  // Now update the polyline according to the new vertices
42538  // The new one representation
42539  TriangleMeshPolyLine *tmp_polyline_pt =
42540  new TriangleMeshPolyLine(vector_vertex_node,bound);
42541 
42542  // Create a temporal "curve section" version of the recently created
42543  // polyline
42544  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
42545 
42546  // Tolerance below which the middle point can be deleted
42547  // (ratio of deflection to element length)
42548  double unrefinement_tolerance=
42549  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42550 
42551  // Tolerance to add points
42552  double refinement_tolerance=
42553  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42554 
42555  // Establish refinement and unrefinement tolerance
42556  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42557  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42558 
42559  // Establish the maximum length constraint
42560  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
42561  tmp_polyline_pt->set_maximum_length(maximum_length);
42562 
42563  if (n_vertex >= 2)
42564  {
42565  // Pass the connection information from the old polyline to the
42566  // new one
42567  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42568  tmp_curve_section_pt);
42569  }
42570 
42571  //Now update the polyline according to the new vertices but first
42572  //check if the object is allowed to delete the representation or
42573  //if it should be done by other object
42574  bool delete_it_on_destructor = false;
42575 
42576  std::set<TriangleMeshCurveSection*>::iterator it =
42577  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42578 
42579  if (it!=this->Free_curve_section_pt.end())
42580  {
42581  this->Free_curve_section_pt.erase(it);
42582  delete open_curve_pt->curve_section_pt(cs);
42583  delete_it_on_destructor = true;
42584  }
42585 
42586  // *****************************************************************
42587  // Copying the new representation
42588  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42589 
42590  // Update the Boundary - Polyline map
42591  this->Boundary_curve_section_pt[bound]=open_curve_pt->curve_section_pt(cs);
42592 
42593  if (delete_it_on_destructor)
42594  {
42595  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
42596  }
42597 
42598 #ifdef OOMPH_HAS_MPI
42599 
42600  // If there are not sub-boundaries mark the boundary if need to be
42601  // trated as shared or as internal boundary
42602  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42603  {
42604  // Clear all previous stored data
42605  this->Boundary_marked_as_shared_boundary[bound].clear();
42606 
42607  // .. and store the flag for the boundary
42608  this->Boundary_marked_as_shared_boundary[bound].push_back(
42609  internal_to_shared_boundary[0]);
42610  }
42611  // --------- Stuff for the sub_boundaries ----- Begin section --------
42612  // Verify if need to deal with sub_boundaries
42613  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42614  {
42615  // Create temporary representations for the boundaries, only to
42616  // create the mesh when calling Triangle
42617  // Clear all previous stored data
42618  this->Boundary_subpolylines[bound].clear();
42619  // Now create storage for the sub-boundaries
42620  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42621 
42622  // Clear all previous stored data
42623  this->Boundary_marked_as_shared_boundary[bound].clear();
42624  // Create storage to mark the internal boundaries as shared
42625  // boundaries
42626  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
42627  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42628  {
42629  // Now update the polyline according to the sub set of
42630  // vertices, set the chunk number of the polyline
42631  TriangleMeshPolyLine *sub_tmp_polyline_pt =
42632  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
42633 
42634  // Add the sub-polyline to the container to represent the
42635  // boundary in parts
42636  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42637 
42638  // Copy the flag that mark the boundary as internal or as
42639  // shared bound
42640  this->Boundary_marked_as_shared_boundary[bound][isub] =
42641  internal_to_shared_boundary[isub];
42642 
42643  // No need to send the unrefinement/refinement and maximum
42644  // length constraints since these are only temporary
42645  // representations
42646 
42647  }
42648 
42649  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42650  // --------- Stuff for the sub_boundaries ----- End section ---------
42651 #endif // OOMPH_HAS_MPI
42652 
42653  } // update polyline representation
42654 
42655  // Delete the allocated memory for the geometric object
42656  // that represents the curvilinear boundary
42657  delete mesh_geom_obj_pt;
42658 
42659  } // npolyline
42660 
42661  // Cleanup the face mesh
42662  for(unsigned p = 0; p < ncurve_section; p++)
42663  {
42664  face_mesh_pt[p]->flush_node_storage();
42665  delete face_mesh_pt[p];
42666  }
42667 
42668 }
42669 
42670 #ifdef OOMPH_HAS_MPI
42671 //======================================================================
42672 /// \short Updates the shared polylines representation after restart
42673 //======================================================================
42674 template <class ELEMENT>
42676 update_shared_curve_after_restart(Vector<TriangleMeshPolyLine*>
42677  &vector_polyline_pt)
42678 {
42679  // Go through all the shared boundaries/polylines
42680  const unsigned npolylines = vector_polyline_pt.size();
42681  for (unsigned pp = 0; pp < npolylines; pp++)
42682  {
42683  // Get the boundary of the current polyline
42684  const unsigned b = vector_polyline_pt[pp]->boundary_id();
42685 
42686  // Get the edges of the shared boundary elements that create the
42687  // shared boundary and store the shared boundary elements from where
42688  // were created
42689  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
42690  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
42691 
42692  // Store the nodes that define the edges
42693  Vector<Node*> halo_edge_nodes_pt;
42694  Vector<Node*> nonhalo_edge_nodes_pt;
42695 
42696  // Go through the shared boundary elements and store their edges
42697  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
42698  for (unsigned e = 0; e < nshared_bound_ele; e++)
42699  {
42700  // Get the shared boundary element
42701  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
42702 
42703  // Get the corner nodes, the first three nodes
42704  Node *first_node_pt = current_ele_pt->node_pt(0);
42705  Node *second_node_pt = current_ele_pt->node_pt(1);
42706  Node *third_node_pt = current_ele_pt->node_pt(2);
42707 
42708  // Check if the elements is halo
42709  if (!current_ele_pt->is_halo())
42710  {
42711  // Store the edges
42712  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42713  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42714 
42715  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42716  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42717 
42718  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42719  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42720 
42721  // Store the info. of the element used to create these edges
42722  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42723  second_node_pt);
42724  nonhalo_edge_element_pt[edge1] = current_ele_pt;
42725 
42726  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42727  third_node_pt);
42728  nonhalo_edge_element_pt[edge2] = current_ele_pt;
42729 
42730  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42731  first_node_pt);
42732  nonhalo_edge_element_pt[edge3] = current_ele_pt;
42733  }
42734  else
42735  {
42736  // Store the edges
42737  halo_edge_nodes_pt.push_back(first_node_pt);
42738  halo_edge_nodes_pt.push_back(second_node_pt);
42739 
42740  halo_edge_nodes_pt.push_back(second_node_pt);
42741  halo_edge_nodes_pt.push_back(third_node_pt);
42742 
42743  halo_edge_nodes_pt.push_back(third_node_pt);
42744  halo_edge_nodes_pt.push_back(first_node_pt);
42745 
42746  // Store the info. of the element used to create these edges
42747  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42748  second_node_pt);
42749  halo_edge_element_pt[edge1] = current_ele_pt;
42750 
42751  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42752  third_node_pt);
42753  halo_edge_element_pt[edge2] = current_ele_pt;
42754 
42755  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42756  first_node_pt);
42757  halo_edge_element_pt[edge3] = current_ele_pt;
42758  }
42759 
42760  } // for (e < nshared_bound_ele)
42761 
42762  // Filter the edges that give rise to a shared boundary
42763 
42764  // Mark the done edges
42765  std::map<std::pair<Node*,Node*>, bool> edge_done;
42766 
42767  // Storage for the edges shared by the elements
42768  Vector<std::pair<Node*, Node*> > unsorted_edges;
42769 
42770  // Storage for the elements that created the unsorted edges (two
42771  // elements, one at each side of the shared boundary)
42772  Vector<Vector<FiniteElement*> > unsorted_edges_elements_pt;
42773 
42774  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
42775  for (unsigned i = 0; i < nnonhalo_edge_nodes; i+=2)
42776  {
42777  Vector<Node*> currenti_edge(2);
42778  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
42779  currenti_edge[1] = nonhalo_edge_nodes_pt[i+1];
42780 
42781  // Create the edge (both nodes that make the edge)
42782  std::pair<Node*, Node*> new_edge =
42783  std::make_pair(currenti_edge[0], currenti_edge[1]);
42784 
42785  if (!edge_done[new_edge])
42786  {
42787  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
42788  for (unsigned j = 0; j < nhalo_edge_nodes; j+=2)
42789  {
42790  Vector<Node*> currentj_edge(2);
42791  currentj_edge[0] = halo_edge_nodes_pt[j];
42792  currentj_edge[1] = halo_edge_nodes_pt[j+1];
42793 
42794  // Comparing pointer of nodes
42795  if (currenti_edge[0] == currentj_edge[0] &&
42796  currenti_edge[1] == currentj_edge[1])
42797  {
42798  // Store the edge in the proper container
42799  unsorted_edges.push_back(new_edge);
42800 
42801  // Get the elements associated with the edges
42802  Vector<FiniteElement*> tmp_edge_element_pt;
42803 
42804  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42805  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
42806 
42807  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42808  tmp_edge_element_pt.push_back(halo_ele_pt);
42809 
42810  // Store the elements associated with the edge
42811  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42812 
42813  // Mark the edge as done
42814  edge_done[new_edge] = true;
42815 
42816  // Break the loop for (j < nedge_node)
42817  break;
42818 
42819  } // equal edge
42820 
42821  // Comparing pointer of nodes (reversed)
42822  else if (currenti_edge[0] == currentj_edge[1] &&
42823  currenti_edge[1] == currentj_edge[0])
42824  {
42825  // Create the edge (both nodes that make the edge)
42826  std::pair<Node*, Node*> new_edge =
42827  std::make_pair(currenti_edge[0], currenti_edge[1]);
42828 
42829  // Store the edge in the proper container
42830  unsorted_edges.push_back(new_edge);
42831 
42832  // Create the (reversed) edge (both nodes that make the edge)
42833  std::pair<Node*, Node*> rev_new_edge =
42834  std::make_pair(currentj_edge[0], currentj_edge[1]);
42835 
42836  // Get the elements associated with the edge
42837  Vector<FiniteElement*> tmp_edge_element_pt;
42838 
42839  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42840  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
42841 
42842  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42843  tmp_edge_element_pt.push_back(halo_ele_pt);
42844 
42845  // Store the elements associated with the edge
42846  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42847 
42848  // Mark the edge as done
42849  edge_done[new_edge] = true;
42850 
42851  // Break the loop for (j < nedge_node)
42852  break;
42853 
42854  } // if (equal edge)
42855 
42856  } // for (j < nhalo_edge_nodes)
42857 
42858  } // if (!edge_done[new_edge])
42859 
42860  } // for (i < nnonhalo_edge_nodes)
42861 
42862  // We already have the edges that make the shared boundary (and the
42863  // elements)
42864  // Sort them to create a contiguous boundary
42865 
42866  // Mark the already sorted edges
42867  std::map<std::pair<Node*,Node*>, bool> edge_sorted;
42868 
42869  const unsigned nunsorted_edges = unsorted_edges.size();
42870 
42871 #ifdef PARANOID
42872  // The number of unsorted edges must be the same as the number of
42873  // shared_boundary element / 2
42874  if (nshared_bound_ele / 2 != nunsorted_edges)
42875  {
42876  std::ostringstream error_message;
42877  error_message
42878  << "The number of shared boundary elements (" << nshared_bound_ele
42879  << ") is not the double\nof the number of unsorted edges ("
42880  << nunsorted_edges << ") for the current boundary ("<< b << ")\n\n";
42881  throw OomphLibError(error_message.str(),
42882  "RefineableTriangleMesh::update_shared_curve_after_restart()",
42883  OOMPH_EXCEPTION_LOCATION);
42884  }
42885 #endif
42886 
42887  unsigned nsorted_edges = 0;
42888 
42889  // Storing for the sorting nodes extracted from the edges, and
42890  // then used to update the polyline
42891  std::list<Node*> sorted_nodes;
42892 
42893  // Storing for the edges elements
42894  std::list<FiniteElement*> sorted_edges_elements_pt;
42895 
42896  // Get the root edge
42897  std::pair<Node*,Node*> edge = unsorted_edges[0];
42898  nsorted_edges++;
42899 
42900  // Mark edge as done
42901  edge_sorted[edge] = true;
42902 
42903  // The initial and final node on the list
42904  Node *first_node_pt = edge.first;
42905  Node *last_node_pt = edge.second;
42906 
42907  // Push back on the list the new edge (nodes)
42908  sorted_nodes.push_back(first_node_pt);
42909  sorted_nodes.push_back(last_node_pt);
42910 
42911  // Store the elements for the current edge
42912  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
42913  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
42914 
42915  // Iterate while the number of sorted edges be less than the number of
42916  // unsorted edges
42917  while (nsorted_edges < nunsorted_edges)
42918  {
42919  // Flag to indicate when a node was added
42920  bool node_added = false;
42921 
42922  // Start from the next edge since we have already added the
42923  // previous one as the initial edge
42924  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
42925  {
42926  edge = unsorted_edges[iedge];
42927 
42928  // If edge not done
42929  if (!edge_sorted[edge])
42930  {
42931  // Get each individual node
42932  Node* left_node_pt = edge.first;
42933  Node* right_node_pt = edge.second;
42934 
42935  if (left_node_pt == first_node_pt)
42936  {
42937  // Push front the new node
42938  sorted_nodes.push_front(right_node_pt);
42939  first_node_pt = right_node_pt;
42940  node_added = true;
42941 
42942  // Store the elements for the current edge
42943  sorted_edges_elements_pt.push_front(
42944  unsorted_edges_elements_pt[iedge][1]);
42945  sorted_edges_elements_pt.push_front(
42946  unsorted_edges_elements_pt[iedge][0]);
42947  }
42948  else if (left_node_pt == last_node_pt)
42949  {
42950  // Push back the new node
42951  sorted_nodes.push_back(right_node_pt);
42952  last_node_pt = right_node_pt;
42953  node_added = true;
42954 
42955  // Store the elements for the current edge
42956  sorted_edges_elements_pt.push_back(
42957  unsorted_edges_elements_pt[iedge][0]);
42958  sorted_edges_elements_pt.push_back(
42959  unsorted_edges_elements_pt[iedge][1]);
42960  }
42961  else if (right_node_pt == first_node_pt)
42962  {
42963  // Push front the new node
42964  sorted_nodes.push_front(left_node_pt);
42965  first_node_pt = left_node_pt;
42966  node_added = true;
42967 
42968  // Store the elements for the current edge
42969  sorted_edges_elements_pt.push_front(
42970  unsorted_edges_elements_pt[iedge][1]);
42971  sorted_edges_elements_pt.push_front(
42972  unsorted_edges_elements_pt[iedge][0]);
42973  }
42974  else if (right_node_pt == last_node_pt)
42975  {
42976  // Push back the new node
42977  sorted_nodes.push_back(left_node_pt);
42978  last_node_pt = left_node_pt;
42979  node_added = true;
42980 
42981  // Store the elements for the current edge
42982  sorted_edges_elements_pt.push_back(
42983  unsorted_edges_elements_pt[iedge][0]);
42984  sorted_edges_elements_pt.push_back(
42985  unsorted_edges_elements_pt[iedge][1]);
42986  }
42987 
42988  if (node_added)
42989  {
42990  // Mark as done only if one of its nodes has been
42991  // added to the list
42992  edge_sorted[edge] = true;
42993  nsorted_edges++;
42994 
42995  // Break the for
42996  break;
42997  }
42998 
42999  } // if (!edge_done[edge])
43000  } // for (iedge < nunsorted_edges)
43001  } // while (nsorted_edges < nunsorted_edges)
43002 
43003  // At this point we already have a sorted list of nodes, get the
43004  // vertices from them and store them in a vector container
43005 
43006  // Get the number of nodes on the list
43007  unsigned nvertex = sorted_nodes.size();
43008  // The vector to store the vertices (assign space)
43009  Vector<Vector<double> > polyline_vertices(nvertex);
43010 
43011  // Copy the vertices of the nodes
43012  unsigned counter = 0;
43013  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43014  it_nodes != sorted_nodes.end();
43015  it_nodes++)
43016  {
43017  polyline_vertices[counter].resize(2);
43018  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43019  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43020  counter++;
43021  }
43022 
43023  // Before going to the unrefinement or refinement process check that
43024  // all processors start from the same vertex. Start from the bottom
43025  // left vertex
43026  if (polyline_vertices[nvertex-1][1] < polyline_vertices[0][1])
43027  {
43028  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43029  }
43030  else if (polyline_vertices[nvertex-1][1] == polyline_vertices[0][1])
43031  {
43032  if (polyline_vertices[nvertex-1][0] < polyline_vertices[0][0])
43033  {
43034  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43035  }
43036  }
43037 
43038  // Create the polyline associated with this edge
43039  TriangleMeshPolyLine *new_polyline_pt =
43040  new TriangleMeshPolyLine(polyline_vertices, b);
43041 
43042  // Get the curve section representation
43043  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
43044 
43045  // Copy the connection information from the old shared polyline
43046  // to the new one
43047  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43048 
43049  //Now update the polyline according to the new vertices but first
43050  //check if the object is allowed to delete the representation
43051  //or if it should be done by other object
43052  bool delete_it_on_destructor = false;
43053 
43054  // Establish the element as being deleted by the destructor of
43055  // the class
43056  std::set<TriangleMeshCurveSection*>::iterator it =
43057  this->Free_curve_section_pt.find(curve_section_pt);
43058 
43059  if (it!=this->Free_curve_section_pt.end())
43060  {
43061  this->Free_curve_section_pt.erase(it);
43062  delete curve_section_pt;
43063  delete_it_on_destructor = true;
43064  }
43065 
43066  // Copy the new representation
43067  vector_polyline_pt[pp] = new_polyline_pt;
43068 
43069  // Get the new curve section representation
43070  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
43071 
43072  // Update the Boundary - Polyline map
43073  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43074 
43075  if (delete_it_on_destructor)
43076  {
43077  this->Free_curve_section_pt.insert(new_curve_section_pt);
43078  }
43079 
43080  } // for (pp < npoly)
43081 
43082 }
43083 
43084 //===================================================================
43085 // \short Fill the boundary elements structures when dealing with
43086 // shared boundaries that overlap internal boundaries. Document the
43087 // number of elements on the shared boundaries that go to internal
43088 // boundaries
43089 //===================================================================
43090 template <class ELEMENT>
43093 {
43094  // Dummy file
43095  std::ofstream some_file;
43096  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43097 }
43098 
43099 //===================================================================
43100 // \short Fill the boundary elements structures when dealing with
43101 // shared boundaries that overlap internal boundaries
43102 //===================================================================
43103 template <class ELEMENT>
43106  std::ofstream& outfile)
43107 {
43108  // Get the number of processors
43109  const unsigned nproc = this->communicator_pt()->nproc();
43110  // Get the rank of the current processor
43111  unsigned my_rank = this->communicator_pt()->my_rank();
43112 
43113  // Temporal name for the shared boundary overlaps structure
43114  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43115  this->Shared_boundary_overlaps_internal_boundary;
43116 
43117  // Register the internal boundary elements that where found to be
43118  // overlapped by shared boundaries
43119  std::set<unsigned> internal_boundary_overlaped;
43120 
43121  // Document the number of elements and nodes associated to the
43122  // boundaries before filling elements and nodes
43123  if (outfile.is_open())
43124  {
43125  const unsigned nbound = this->nboundary();
43126  outfile << "Number of boundaries: " << nbound << "\n\n";
43127  outfile << "Number of elements and nodes associated to each "
43128  << "boundary before\nfilling elements and nodes\n\n";
43129  for (unsigned i = 0; i < nbound; i++)
43130  {
43131  outfile << "Boundary (" << i << ") Elements ("
43132  << this->nboundary_element(i) << ") " << "Nodes ("
43133  << this->nboundary_node(i) << ")\n";
43134  }
43135  }
43136 
43137  // Storage for the shared boundaries in this processor
43138  std::set<unsigned> shared_boundaries_in_this_processor;
43139 
43140  // Get the shared boundaries that this processor has with other
43141  // processors
43142  for (unsigned iproc = 0; iproc < nproc; iproc++)
43143  {
43144  // Work with other processors only
43145  if (iproc != my_rank)
43146  {
43147  // Get the number of boundaries shared with the "iproc"-th processor
43148  unsigned nshared_boundaries_with_iproc =
43149  this->nshared_boundaries(my_rank, iproc);
43150 
43151  if (nshared_boundaries_with_iproc > 0)
43152  {
43153  // Get the boundaries ids shared with "iproc"-th processor
43154  Vector<unsigned> bound_shared_with_iproc;
43155  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank,
43156  iproc);
43157 
43158  // Loop over shared boundaries with "iproc"-th processor
43159  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43160  {
43161  unsigned bnd_id = bound_shared_with_iproc[bs];
43162  shared_boundaries_in_this_processor.insert(bnd_id);
43163  }
43164  }
43165  }
43166  }
43167 
43168  // ------------------------------------------------------------------
43169  // Copy the boundary elements and nodes from the shared boundary to
43170  // the internal boundary it overlaps
43171  // ------------------------------------------------------------------
43172  // Go through the shared boundaries that overlap internal boundaries
43173  for (std::map<unsigned, unsigned>::iterator it =
43174  shd_bnd_over_int_bnd.begin(); it != shd_bnd_over_int_bnd.end(); it++)
43175  {
43176  // The shared boundary id that overlaps with an internal boundary
43177  const unsigned shd_bnd_id = (*it).first;
43178  // The internal boundary overlapped by the shared boundary
43179  const unsigned int_bnd_id = (*it).second;
43180 
43181  // Check if the shared boundary exist in this processor
43182  std::set<unsigned>::iterator it_set =
43183  shared_boundaries_in_this_processor.find(shd_bnd_id);
43184  if (it_set != shared_boundaries_in_this_processor.end())
43185  {
43186  internal_boundary_overlaped.insert(int_bnd_id);
43187 
43188  // -----------------------------------------------------------------
43189  // First work the nodes of the shared boundaries that should be
43190  // added to the internal boundaries
43191  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43192 
43193  // Document the number of nodes that will be passed to the internal
43194  // boundary from the current shared boundary
43195  if (outfile.is_open())
43196  {
43197  outfile << "\nPass info. from shared (" << shd_bnd_id
43198  << ") to internal (" << int_bnd_id << ")\n";
43199  outfile << "Number of shared boundary nodes: "
43200  << nbnd_node_shd_bnd << "\n";
43201  }
43202 
43203  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43204  {
43205  // Get the boundary node
43206  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43207  // Add the node to the internal boundary
43208  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43209  }
43210 
43211  // -----------------------------------------------------------------
43212  // Second work the boundary elements
43213  // Get the number of boundary elements that should be copied to the
43214  // internal boundary
43215  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43216 
43217  // Document the number of elements that will be passed to the
43218  // internal boundary from the current shared boundary
43219  if (outfile.is_open())
43220  {
43221  outfile << "Number of shared boundary elements: "
43222  << nbnd_ele_shd_bnd << "\n\n";
43223  }
43224 
43225  // Go through the boundary elements in the shrared boundary and add
43226  // them to the boundary elements of the internal boundary
43227  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43228  {
43229  // Get the boundary element
43230  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43231  // Add the element to the boundary elements storage of the
43232  // internal boundary
43233  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43234  // Get the face index of the boundary
43235  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43236  // Add the face index to the storage of the boundary
43237  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43238 
43239  } // for (ie < nbnd_ele_shd_bnd)
43240 
43241  // If there are regions we need to fill the storage for regions too
43242  const unsigned nregions = this->nregion();
43243  if (nregions > 1)
43244  {
43245  for (unsigned ir = 0 ; ir < nregions; ir++)
43246  {
43247  // Get the region attribute
43248  const unsigned region_id =
43249  static_cast<unsigned>(this->Region_attribute[ir]);
43250 
43251  // Loop over all elements on boundaries in region ir
43252  const unsigned nele_ir = this->nboundary_element_in_region(shd_bnd_id,
43253  region_id);
43254  for (unsigned ier = 0; ier < nele_ir; ier++)
43255  {
43256  // Get the boundary element in current region
43257  FiniteElement* bnd_ele_pt =
43258  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43259  // Add the boundary element to the internal boundary in the
43260  // region
43261  this->Boundary_region_element_pt[int_bnd_id][region_id].
43262  push_back(bnd_ele_pt);
43263 
43264  // Get the face index of the boundary
43265  int face_index =
43266  this->face_index_at_boundary_in_region(shd_bnd_id, region_id, ier);
43267  // Add the face index to the storage of the boundary region
43268  this->Face_index_region_at_boundary[int_bnd_id][region_id].
43269  push_back(face_index);
43270 
43271  } // for (ier < nele_ir)
43272 
43273  } // for (ir < nregions)
43274 
43275  } // if (nregions > 1)
43276 
43277  } // if (the shared boundary appears in the current processor)
43278 
43279  } // for (loop over the shared bound that overlap an internal bound)
43280 
43281  // Document the number of elements and nodes associated to the
43282  // boundaries after filling elements and nodes
43283  if (outfile.is_open())
43284  {
43285  const unsigned nbound = this->nboundary();
43286  outfile << "Number of boundaries: " << nbound << "\n\n";
43287  outfile << "Number of elements and nodes associated to each "
43288  << "boundary after\nfilling elements and nodes\n\n";
43289  for (unsigned i = 0; i < nbound; i++)
43290  {
43291  outfile << "Boundary (" << i << ") Elements ("
43292  << this->nboundary_element(i) << ")" << " Nodes ("
43293  << this->nboundary_node(i) << ")\n";
43294  }
43295  }
43296 
43297  // ------------------------------------------------------------------
43298  // Finally, re-setup the boundary coordinates for the new nodes on
43299  // the overlaped internal boundaries
43300  // ------------------------------------------------------------------
43301  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43302  it != internal_boundary_overlaped.end(); it++)
43303  {
43304  const unsigned overlaped_internal_bnd_id = (*it);
43305 
43306  // Re-setup boundary coordinates
43307  this->template setup_boundary_coordinates<ELEMENT>(overlaped_internal_bnd_id);
43308  }
43309 
43310 }
43311 
43312 #endif // #ifdef OOMPH_HAS_MPI
43313 
43314  //======================================================================
43315  /// Move the boundary nodes onto the boundary defined by the old mesh
43316  //======================================================================
43317  template <class ELEMENT>
43319  RefineableTriangleMesh<ELEMENT>* &new_mesh_pt, const unsigned &b)
43320  {
43321 
43322  // Quick return
43323  if (!Boundary_coordinate_exists[b])
43324  {
43325  return;
43326  }
43327 
43328  //Firstly we set the boundary coordinates of the new nodes
43329  //In case the mapping between the geometric object's intrinsic coordinate
43330  //and the arc-length coordinate is nonlinear. This is only an approximation,
43331  //but it will ensure that the nodes that were input to triangle will
43332  //retain exactly the same boundary coordinates and then linear interpolation
43333  //is used between those values for any newly created nodes.
43334 
43335  // We need to get the boundary nodes from the boundary face
43336  // elements since the "multi_domain" methods add nodes to the
43337  // "Boundary_node_pt" structure which have no boundary coordinates
43338  // assigned
43339  std::set<Node*> tmp_boundary_node_pt;
43340  const unsigned nboundary_ele = this->nboundary_element(b);
43341  for (unsigned e = 0; e < nboundary_ele; e++)
43342  {
43343  // Get the boundary bulk element
43344  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43345 #ifdef OOMPH_HAS_MPI
43346  // Only work with nonhalo elements if the mesh is distributed
43347  if (!bulk_ele_pt->is_halo())
43348  {
43349 #endif
43350  // Get the face index
43351  int face_index = this->face_index_at_boundary(b, e);
43352  // Create the face element
43353  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
43354  bulk_ele_pt, face_index);
43355 
43356  // Get the number of nodes on the face element
43357  const unsigned nnodes = face_ele_pt->nnode();
43358  for (unsigned i = 0; i < nnodes; i++)
43359  {
43360  // Get the nodes in the face elements
43361  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43362  // Add the nodes to the set of boundary nodes
43363  tmp_boundary_node_pt.insert(tmp_node_pt);
43364  } // for (i < nnodes)
43365 
43366  // Free the memory allocated for the face element
43367  delete face_ele_pt;
43368  face_ele_pt = 0;
43369 #ifdef OOMPH_HAS_MPI
43370  } // if (!bulk_ele_pt->is_halo())
43371 #endif
43372 
43373  } // for (e < nboundary_ele)
43374 
43375  // Get the number of boundary nodes
43376  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43377 
43378  // Quick return if there are no nodes
43379  if (n_boundary_node==0)
43380  {
43381 #ifdef OOMPH_HAS_MPI
43382  // Check if we are working with a distributed mesh
43383  if (!this->is_mesh_distributed())
43384  {
43385 #endif
43386  return;
43387 #ifdef OOMPH_HAS_MPI
43388  }
43389  else // The mesh is distributed !!!
43390  {
43391  // Do not forget to participate in the communication
43392  Mesh* face_mesh_pt = new Mesh();
43393  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43394  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43395 
43396  //Delete the allocated memory for the geometric object and face mesh
43397  delete mesh_geom_obj_pt;
43398 
43399  // Flush the nodes from the face mesh to make sure we
43400  // don't delete them (the bulk mesh still needs them!)
43401  face_mesh_pt->flush_node_storage();
43402  delete face_mesh_pt;
43403  return;
43404  }
43405 #endif
43406  } // if (n_boundary_node==0)
43407 
43408  //Create a vector of existing boundary nodes with their boundary
43409  //coordinate as the first entry so that we can use standard sort algorithms
43410  Vector<double> node_coord(3);
43411  Vector<double> b_coord(1);
43412 
43413  Vector<Vector<double> > old_boundary_node(n_boundary_node);
43414  unsigned tmp_counter = 0;
43415  for(std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43416  it_node != tmp_boundary_node_pt.end(); it_node++, tmp_counter++)
43417  {
43418  Node* nod_pt = (*it_node);
43419  nod_pt->get_coordinates_on_boundary(b,b_coord);
43420  node_coord[0] = b_coord[0];
43421  node_coord[1] = nod_pt->x(0);
43422  node_coord[2] = nod_pt->x(1);
43423  old_boundary_node[tmp_counter] = node_coord;
43424  } // for (it_node != tmp_boundary_node_pt.end())
43425 
43426  //Sort the vector
43427  std::sort(old_boundary_node.begin(),old_boundary_node.end());
43428 
43429  //Set up an equivalent ordered vector for the new nodes, based on the
43430  //current coordinate which is the scaled arc-length.
43431  //Also provide storage for the original node index,
43432  //the mapped coordinate and a flag to indicate whether the mapped
43433  //coordinate has been assigned.
43434  //Get the nodes on the boundary but consider to which segment (which
43435  //may appear in a distributed mesh) they belong
43436  Vector<Vector<Node*> > segment_nodes_pt;
43437 
43438 #ifdef OOMPH_HAS_MPI
43439  // Get the number of segments
43440  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43441 #else
43442  // The number of segments is one since the boundary is not split
43443  // over multiple processors
43444  const unsigned nsegments = 1;
43445 #endif // #ifdef OOMPH_HAS_MPI
43446 
43447 #ifdef OOMPH_HAS_MPI
43448  // Get the total number of nodes on the boundary
43449  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43450 
43451  // Check if we are working with a distributed mesh
43452  if (this->is_mesh_distributed())
43453  {
43454  // If that is the case we need to ensure that the new mesh has
43455  // nodes too, if that is not the case then return
43456  // Quick return if there are no nodes
43457  if (n_new_boundary_node==0)
43458  {
43459  // Do not forget to participate in the communication
43460  Mesh* face_mesh_pt = new Mesh();
43461  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43462  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43463 
43464  //Delete the allocated memory for the geometric object and face mesh
43465  delete mesh_geom_obj_pt;
43466  // Flush the nodes from the face mesh to make sure we
43467  // don't delete them (the bulk mesh still needs them!)
43468  face_mesh_pt->flush_node_storage();
43469  delete face_mesh_pt;
43470  return;
43471  }
43472  }
43473 #endif // #ifdef OOMPH_HAS_MPI
43474 
43475  //Create a vector of boundary nodes that must be moved
43476  Vector<Vector<unsigned> > nodes_to_be_snapped(nsegments);
43477 
43478  // Go through all the segments to assign the snapped zeta coordinates
43479  // for the new nodes
43480  for (unsigned is = 0; is < nsegments; is++)
43481  {
43482 #ifdef OOMPH_HAS_MPI
43483  const unsigned n_new_boundary_segment_node =
43484  new_mesh_pt->nboundary_segment_node(b,is);
43485 #else
43486  const unsigned n_new_boundary_segment_node = new_mesh_pt->nboundary_node(b);
43487 #endif // #ifdef OOMPH_HAS_MPI
43488 
43489  Vector<Vector<double> > new_boundary_node(n_new_boundary_segment_node);
43490  //There will be six data associated with each node
43491  node_coord.resize(6,0.0);
43492  for(unsigned n = 0; n < n_new_boundary_segment_node; n++)
43493  {
43494 #ifdef OOMPH_HAS_MPI
43495  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43496 #else
43497  Node* nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43498 #endif // #ifdef OOMPH_HAS_MPI
43499  nod_pt->get_coordinates_on_boundary(b,b_coord);
43500  node_coord[0] = b_coord[0];
43501  node_coord[1] = nod_pt->x(0);
43502  node_coord[2] = nod_pt->x(1);
43503  node_coord[3] = n;
43504  new_boundary_node[n] = node_coord;
43505  } // for (n < n_new_boundary_segment_node)
43506 
43507  //Sort the new boundary nodes based on their arc-length coordinate
43508  std::sort(new_boundary_node.begin(),new_boundary_node.end());
43509 
43510  //We now have two sets of nodes ordered by a coordinate that acts in the
43511  //same direction and has the same limits.
43512 
43513  //Loop over the vector of new nodes and allocate exactly the same
43514  //coordinate as the old nodes at points of coincidence
43515  unsigned old_index = 0;
43516  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43517  {
43518  //Loop over the set of old nodes and if the x and y coordinates
43519  //coincide with the new node copy accross the new boundary coordinate
43520  for(unsigned m=old_index;m<n_boundary_node;++m)
43521  {
43522  if(
43523  (std::fabs(old_boundary_node[m][1]-new_boundary_node[n][1])<1.0e-14)
43524  &&
43525  (std::fabs(old_boundary_node[m][2]-new_boundary_node[n][2])<1.0e-14))
43526  {
43527  //Store the boundary coordinate from the old mesh
43528  new_boundary_node[n][4] = old_boundary_node[m][0];
43529  //Say that it has been stored
43530  new_boundary_node[n][5] = 1.0;
43531  //For efficiency, we can start the iteration from here next
43532  //time round because both vectors are ordered
43533  old_index = m;
43534  break;
43535  }
43536  }
43537  }
43538 
43539  //Check that the end-points have new boundary coordinates allocated
43540 #ifdef PARANOID
43541  if((new_boundary_node[0][5]==0.0) ||
43542  (new_boundary_node[n_new_boundary_segment_node-1][5] == 0.0))
43543  {
43544  std::ostringstream error_stream;
43545  error_stream
43546  <<"New boundary coordinates not found for the first and/or last "
43547  <<"nodes\n"
43548  <<"on the boundary " << b << ". This should not happen because "
43549  <<"these\nlimits should have been setup in the constructor\n";
43550  error_stream
43551  <<"The distance between the new and old nodes is probably outside\n"
43552  <<"our tolerance.\n";
43553  error_stream.precision(20);
43554  error_stream << "Old boundaries: \n";
43555  error_stream <<
43556  old_boundary_node[0][1] << " " << old_boundary_node[0][2]
43557  << " : " <<
43558  old_boundary_node[n_boundary_node-1][1] << " " <<
43559  old_boundary_node[n_boundary_node-1][2] << "\n";
43560  error_stream << "New boundaries: \n" <<
43561  new_boundary_node[0][1] << " " << new_boundary_node[0][2] << " : " <<
43562  new_boundary_node[n_new_boundary_segment_node-1][1] << " " <<
43563  new_boundary_node[n_new_boundary_segment_node-1][2] << "\n";
43564  OomphLibWarning(error_stream.str(),
43565  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43566  OOMPH_EXCEPTION_LOCATION);
43567  }
43568 #endif
43569 
43570  // This is only true if the boundary is not splitted among the
43571  // processors
43572  if (!this->is_mesh_distributed())
43573  {
43574  //The end points should always be present, so we
43575  //can (and must) always add them in exactly
43576  new_boundary_node[0][4] = new_boundary_node[0][0];
43577 
43578  /// Correct!? Because assigned again below
43579  new_boundary_node[n_new_boundary_segment_node-1][4] =
43580  new_boundary_node[0][5] = 1.0;
43581 
43582  new_boundary_node[n_new_boundary_segment_node-1][4] =
43583  new_boundary_node[n_new_boundary_segment_node-1][0];
43584  new_boundary_node[n_new_boundary_segment_node-1][5] = 1.0;
43585  }
43586 
43587  //Now loop over the interior nodes again and
43588  //use linear interpolation to fill in any unassigned coordiantes
43589  for(unsigned n=1;n<n_new_boundary_segment_node-1;++n)
43590  {
43591  //If the new boundary coordinate has NOT been allocated
43592  if(new_boundary_node[n][5]==0.0)
43593  {
43594  //Add its (unsorted) node number to the list
43595  nodes_to_be_snapped[is].push_back(
43596  static_cast<unsigned>(new_boundary_node[n][3]));
43597 
43598  //We assume that the previous nodal value has been assigned
43599  //and read out the old and new boundary coordinates
43600  double zeta_old_low = new_boundary_node[n-1][0];
43601  double zeta_new_low = new_boundary_node[n-1][4];
43602 
43603  //Loop over the nodes above the current node until
43604  //we find the next one that has been allocated
43605  for(unsigned m=n+1;m<n_new_boundary_segment_node;++m)
43606  {
43607  if(new_boundary_node[m][5]==1.0)
43608  {
43609  //Read out the old boundary coordinate
43610  double zeta_old_high = new_boundary_node[m][0];
43611  double zeta_new_high = new_boundary_node[m][4];
43612  //Use linear interpolation to assign the new boundary coordinate
43613  double frac = (new_boundary_node[n][0] - zeta_old_low)/
43614  (zeta_old_high - zeta_old_low);
43615  new_boundary_node[n][4] = zeta_new_low
43616  + frac*(zeta_new_high - zeta_new_low);
43617  new_boundary_node[n][5] = 1.0;
43618  break;
43619  }
43620  }
43621  }
43622  }
43623 
43624  //Loop over all the nodes and set the new boundary coordinate
43625  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43626  {
43627  if(new_boundary_node[n][5]==0)
43628  {
43629  throw OomphLibError(
43630  "New boundary coordinate not assigned\n",
43631  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43632  OOMPH_EXCEPTION_LOCATION);
43633  }
43634 
43635 #ifdef OOMPH_HAS_MPI
43636  //get the old coordinate
43637  new_mesh_pt->boundary_segment_node_pt(
43638  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43639  ->get_coordinates_on_boundary(b,b_coord);
43640  //Set the new coordinate
43641  b_coord[0] = new_boundary_node[n][4];
43642  new_mesh_pt->boundary_segment_node_pt(
43643  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43644  ->set_coordinates_on_boundary(b,b_coord);
43645 #else
43646  //get the old coordinate
43647  new_mesh_pt->boundary_node_pt(
43648  b,static_cast<unsigned>(new_boundary_node[n][3]))
43649  ->get_coordinates_on_boundary(b,b_coord);
43650  //Set the new coordinate
43651  b_coord[0] = new_boundary_node[n][4];
43652  new_mesh_pt->boundary_node_pt(
43653  b,static_cast<unsigned>(new_boundary_node[n][3]))
43654  ->set_coordinates_on_boundary(b,b_coord);
43655 #endif // #ifdef OOMPH_HAS_MPI
43656 
43657  }
43658 
43659  } // for (is < nsegments)
43660 
43661  Mesh* face_mesh_pt = new Mesh();
43662  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43663 
43664  //Now that the coordinates have been set up we can do the snapping
43665  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
43666 
43667  //Now assign the new nodes positions based on the old meshes
43668  //potentially curvilinear boundary (its geom object incarnation)
43669  Vector<double> new_x(2);
43670 
43671  //Loop over the nodes that need to be snapped
43672  for(unsigned is = 0; is < nsegments; is++)
43673  {
43674  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
43675 
43676  for (unsigned in = 0; in < nnodes_to_snap; in++)
43677  {
43678  //Read out the boundary node number
43679  unsigned n = nodes_to_be_snapped[is][in];
43680 #ifdef OOMPH_HAS_MPI
43681  //Get the boundary coordinate of all new nodes
43682  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43683 #else
43684  //Get the boundary coordinate of all new nodes
43685  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43686 #endif // #ifdef OOMPH_HAS_MPI
43687 
43688  nod_pt->get_coordinates_on_boundary(b,b_coord);
43689  //Let's find boundary coordinates of the new node
43690  mesh_geom_obj_pt->position(b_coord,new_x);
43691 
43692  //Now snap to the boundary
43693  for(unsigned i=0;i<2;i++)
43694  {
43695  nod_pt->x(i) = new_x[i];
43696  }
43697  }
43698  }
43699 
43700  //Delete the allocated memory for the geometric object and face mesh
43701  delete mesh_geom_obj_pt;
43702  // Flush the nodes from the face mesh to make sure we
43703  // don't delete them (the bulk mesh still needs them!)
43704  face_mesh_pt->flush_node_storage();
43705  delete face_mesh_pt;
43706 
43707  //Fix up the elements adjacent to the boundary
43708 
43709  // Dummy six node element for sorting out bubble node for
43710  // seven node enriched quadratic triangles
43711  TElement<2,3> dummy_six_node_element;
43712  for (unsigned j=0;j<6;j++)
43713  {
43714  dummy_six_node_element.construct_node(j);
43715  }
43716 
43717  //This should definitely become a triangular element member function
43718  //Loop over elements
43719  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
43720  for(unsigned e=0;e<n_bound_el;e++)
43721  {
43722  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b,e);
43723 
43724  // Deal with different numbers of nodes separately
43725  unsigned nnod=el_pt->nnode();
43726 
43727 // #ifdef PARANOID
43728 // // Flag to indicate if we successully classified/dealt with the element
43729 // bool success=false;
43730 // #endif
43731 
43732  // Simplex element: Nothing to be done other than error checking
43733  if (nnod==3)
43734  {
43735 #ifdef PARANOID
43736  // Try to cast to a simplex element
43737  TElement<2,2>* t_el_pt=dynamic_cast<TElement<2,2>*>(el_pt);
43738  if (t_el_pt==0)
43739  {
43740  throw OomphLibError(
43741  "Have a three-noded element that's not a TElement<2,2>",
43742  OOMPH_CURRENT_FUNCTION,
43743  OOMPH_EXCEPTION_LOCATION);
43744  }
43745  // If I get there I must not have thrown :)
43746  //success=true;
43747 #endif
43748  }
43749  // Quadratic element (or enriched quadratic)
43750 
43751  else if ((nnod==6)||(nnod==7))
43752  {
43753 
43754 #ifdef PARANOID
43755  // Try to cast to a quadratic element
43756  TElement<2,3>* t_el_pt=dynamic_cast<TElement<2,3>*>(el_pt);
43757  if (t_el_pt==0)
43758  {
43759  if (nnod==6)
43760  {
43761  throw OomphLibError(
43762  "Have a six-noded element that's not a TElement<2,3>",
43763  OOMPH_CURRENT_FUNCTION,
43764  OOMPH_EXCEPTION_LOCATION);
43765  }
43766  else
43767  {
43768  throw OomphLibError(
43769  "Have a seven-noded element that's not a TElement<2,3>",
43770  OOMPH_CURRENT_FUNCTION,
43771  OOMPH_EXCEPTION_LOCATION);
43772  }
43773  }
43774  // If I get there I must not have thrown :)
43775  //success=true;
43776 #endif
43777  // Deal with six noded stuff for all (normal and enriched) elements
43778 
43779  ///----------------------------------------------------------------
43780  /// Repositioning of mid-side nodes
43781  ///----------------------------------------------------------------
43782 
43783  //Side between 0 and 1
43784  if(el_pt->node_pt(3)->is_on_boundary(b))
43785  {
43786  //Make sure that the node I'm about to move is NOT on
43787  //a boundary
43788  if(!el_pt->node_pt(5)->is_on_boundary())
43789  {
43790  //Reset the internal nodes
43791  for(unsigned i=0;i<2;i++)
43792  {
43793  el_pt->node_pt(5)->x(i) =
43794  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43795  }
43796  }
43797  //Make sure that the node I'm about to move is NOT on
43798  //a boundary
43799  if(!el_pt->node_pt(4)->is_on_boundary())
43800  {
43801  //Reset the internal nodes
43802  for(unsigned i=0;i<2;i++)
43803  {
43804  el_pt->node_pt(4)->x(i) =
43805  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43806  }
43807  }
43808  }
43809 
43810  //Side between 1 and 2
43811  if(el_pt->node_pt(4)->is_on_boundary(b))
43812  {
43813  //Make sure that the node I'm about to move is NOT on
43814  //a boundary
43815  if(!el_pt->node_pt(5)->is_on_boundary())
43816  {
43817  //Reset the internal nodes
43818  for(unsigned i=0;i<2;i++)
43819  {
43820  el_pt->node_pt(5)->x(i) =
43821  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43822  }
43823  }
43824  //Make sure that the node I'm about to move is NOT on
43825  //a boundary
43826  if(!el_pt->node_pt(3)->is_on_boundary())
43827  {
43828  //Reset the internal nodes
43829  for(unsigned i=0;i<2;i++)
43830  {
43831  el_pt->node_pt(3)->x(i) =
43832  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43833  }
43834  }
43835  }
43836 
43837  //Side between 0 and 2
43838  if(el_pt->node_pt(5)->is_on_boundary(b))
43839  {
43840  //Make sure that the node I'm about to move is NOT on
43841  //a boundary
43842  if(!el_pt->node_pt(4)->is_on_boundary())
43843  {
43844  //Reset the internal nodes
43845  for(unsigned i=0;i<2;i++)
43846  {
43847  el_pt->node_pt(4)->x(i) =
43848  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43849  }
43850  }
43851  //Make sure that the node I'm about to move is NOT on
43852  //a boundary
43853  if(!el_pt->node_pt(3)->is_on_boundary())
43854  {
43855  //Reset the internal nodes
43856  for(unsigned i=0;i<2;i++)
43857  {
43858  el_pt->node_pt(3)->x(i) =
43859  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43860  }
43861  }
43862  }
43863 
43864  // If it's seven noded it's likely to be an enriched one: Deal with
43865  // the central (bubble) node
43866  if (nnod==7)
43867  {
43868  // Try to cast to an enriched quadratic element
43869  TBubbleEnrichedElement<2,3>* t_el_pt=
43870  dynamic_cast<TBubbleEnrichedElement<2,3>*>(el_pt);
43871  if (t_el_pt==0)
43872  {
43873  throw OomphLibError(
43874  "Have seven-noded element that's not a TBubbleEnrichedElement<2,3>",
43875  OOMPH_CURRENT_FUNCTION,
43876  OOMPH_EXCEPTION_LOCATION);
43877  }
43878 
43879  // Assign the new non-bubble coordinates to the six noded dummy element
43880  for (unsigned j=0;j<6;j++)
43881  {
43882  for (unsigned i=0;i<2;i++)
43883  {
43884  dummy_six_node_element.node_pt(j)->x(i)=el_pt->node_pt(j)->x(i);
43885  }
43886  }
43887 
43888  // Local coordinate of enriched node
43889  unsigned j_enriched=6;
43890  Vector<double> s(2);
43891  el_pt->local_coordinate_of_node(j_enriched,s);
43892 
43893  // Get its position from non-enriched element
43894  Vector<double> x(2);
43895  dummy_six_node_element.interpolated_x(s,x);
43896  el_pt->node_pt(j_enriched)->x(0) = x[0];
43897  el_pt->node_pt(j_enriched)->x(1) = x[1];
43898  }
43899  }
43900  // Any other case cannot be dealt with at the moment
43901 
43902  else
43903  {
43904  std::ostringstream error_stream;
43905  error_stream
43906  << "Cannot deal with this particular " << nnod
43907  << "-noded element yet.\n"
43908  << "Please implement this yourself.\n";
43909  throw OomphLibError(error_stream.str(),
43910 OOMPH_CURRENT_FUNCTION,
43911  OOMPH_EXCEPTION_LOCATION);
43912  }
43913  }
43914 
43915  // Cleanup
43916  for (unsigned j=0;j<6;j++)
43917  {
43918  delete dummy_six_node_element.node_pt(j);
43919  }
43920 
43921  }
43922 
43923 
43924 
43925 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
43926 
43927 }
43928 
43929 #endif
oomph::RefineableTriangleMesh::update_open_curve_using_elements_area
bool update_open_curve_using_elements_area(TriangleMeshOpenCurve *&open_curve_pt, const Vector< double > &target_area)
Updates the open curve but using the elements area instead of the default refinement and unrefinement...
Definition: triangle_mesh.template.cc:38363
oomph::RefineableTriangleMesh::create_polylines_from_polyfiles
void create_polylines_from_polyfiles(const std::string &node_file_name, const std::string &poly_file_name)
Helper function to create polylines and fill associate data.
Definition: triangle_mesh.template.cc:36393
oomph::TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values
void compute_boundary_segments_connectivity_and_initial_zeta_values(const unsigned &b)
Compute the boundary segments connectivity for those boundaries that were splited during the distribu...
Definition: triangle_mesh.template.cc:1842
oomph::TriangleMesh::select_boundary_face_elements
void select_boundary_face_elements(Vector< FiniteElement * > &face_el_pt, const unsigned &b, bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Select face element from boundary using the criteria to decide which of the two face elements should ...
Definition: triangle_mesh.template.cc:5241
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
Definition: triangle_mesh.template.cc:15323
oomph::TriangleMesh::get_halo_elements_on_all_procs
void get_halo_elements_on_all_procs(const unsigned &nproc, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status, std::map< GeneralisedElement *, unsigned > &element_to_global_index, Vector< Vector< Vector< GeneralisedElement * > > > &output_halo_elements_pt)
Creates the halo elements on all processors Gets the halo elements on all processors,...
Definition: triangle_mesh.template.cc:11481
oomph::RefineableTriangleMesh::surface_remesh_for_inner_hole_boundaries
virtual bool surface_remesh_for_inner_hole_boundaries(Vector< Vector< double > > &internal_point_coord, const bool &check_only=false)
Generate a new PSLG representation of the inner hole boundaries. Optional boolean is used to run it a...
Definition: triangle_mesh.template.cc:36204
oomph::classcomp::Tol
static double Tol
Definition: triangle_mesh.template.cc:15033
oomph::RefineableTriangleMesh::restore_polyline_connections_helper
void restore_polyline_connections_helper(TriangleMeshPolyLine *polyline_pt, Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Restore the connections of the specific polyline The vertices numbering on the destination boundaries...
Definition: triangle_mesh.template.cc:33008
oomph::RefineableTriangleMesh::sort_nodes_on_shared_boundaries
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
Definition: triangle_mesh.template.cc:15127
oomph::RefineableTriangleMesh::update_open_curve_after_restart
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
Definition: triangle_mesh.template.cc:41731
oomph::RefineableTriangleMesh::update_shared_curve_using_elements_area
bool update_shared_curve_using_elements_area(Vector< TriangleMeshPolyLine * > &vector_polyline_pt, const Vector< double > &target_areas)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:39607
oomph::TriangleMeshParameters::internal_open_curves_pt
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
Definition: triangle_mesh.template.h:167
oomph::RefineableTriangleMesh::snap_nodes_onto_boundary
void snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
Definition: triangle_mesh.template.cc:43318
oomph::TriangleMeshParameters::internal_closed_curve_pt
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
Definition: triangle_mesh.template.h:158
oomph::TriangleMesh::update_holes_information_helper
void update_holes_information_helper(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< Vector< double > > &output_holes_coordinates)
Keeps those vertices that define a hole, those that are inside closed internal boundaries in the new ...
Definition: triangle_mesh.template.cc:10797
oomph::RefineableTriangleMesh::get_required_nodal_information_load_balance_helper
void get_required_nodal_information_load_balance_helper(Vector< Vector< FiniteElement * > > &f_halo_ele_pt, unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from an haloed node so that a fully-functional ...
Definition: triangle_mesh.template.cc:26530
oomph::RefineableTriangleMesh::create_new_shared_boundaries
void create_new_shared_boundaries(std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< FiniteElement * > > &new_shared_boundary_element_pt, Vector< Vector< unsigned > > &new_shared_boundary_element_face_index)
Creates the new shared boundaries, this method is also in charge of computing the shared boundaries i...
Definition: triangle_mesh.template.cc:22462
oomph::RefineableTriangleMesh::fill_boundary_elements_and_nodes_for_internal_boundaries
void fill_boundary_elements_and_nodes_for_internal_boundaries()
Definition: triangle_mesh.template.cc:43092
oomph::TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary
void re_assign_initial_zeta_values_for_internal_boundary(const unsigned &b, Vector< std::list< FiniteElement * > > &old_segment_sorted_ele_pt, std::map< FiniteElement *, bool > &old_is_inverted)
Re-assign the boundary segments initial zeta (arclength) value for those internal boundaries that wer...
Definition: triangle_mesh.template.cc:4059
oomph::RefineableTriangleMesh::get_required_elemental_information_helper
void get_required_elemental_information_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to get the required elemental information from an haloed element. This info....
Definition: triangle_mesh.template.cc:17796
oomph::RefineableTriangleMesh::get_required_elemental_information_load_balance_helper
void get_required_elemental_information_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, FiniteElement *ele_pt)
Helper function to get the required elemental information from the element to be sent....
Definition: triangle_mesh.template.cc:26100
oomph::RefineableTriangleMesh::max_element_size
double & max_element_size()
Max element size allowed during adaptation.
Definition: triangle_mesh.template.h:2371
oomph::TriangleMesh::create_tmp_polygons_helper
void create_tmp_polygons_helper(Vector< Vector< TriangleMeshPolyLine * > > &polylines_pt, Vector< TriangleMeshPolygon * > &polygons_pt)
Take the polylines from the shared boundaries and create temporary polygon representations of the dom...
Definition: triangle_mesh.template.cc:8515
oomph::RefineableTriangleMesh::load_balance
void load_balance(const Vector< unsigned > &input_target_domain_for_local_non_halo_element)
Performs the load balancing for unstructured meshes, the load balancing strategy is based on mesh mig...
Definition: triangle_mesh.template.cc:20241
oomph::RefineableTriangleMesh::reset_shared_boundary_elements_and_nodes
void reset_shared_boundary_elements_and_nodes(const bool flush_elements=true, const bool update_elements=true, const bool flush_nodes=true, const bool update_nodes=true)
Re-establish the shared boundary elements after the adaptation process (the updating of shared nodes ...
Definition: triangle_mesh.template.cc:15237
oomph::RefineableTriangleMesh::refine_boundary
bool refine_boundary(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, const bool &check_only=false)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:35129
triangle_mesh.template.h
oomph::TriangleMesh::break_loops_on_shared_polyline_helper
void break_loops_on_shared_polyline_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:13099
oomph::RefineableTriangleMesh::min_permitted_angle
double & min_permitted_angle()
Min angle before remesh gets triggered.
Definition: triangle_mesh.template.h:2377
oomph::RefineableTriangleMesh::update_other_proc_shd_bnd_node_helper
void update_other_proc_shd_bnd_node_helper(Node *&new_nod_pt, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< unsigned > &other_processor_1, Vector< unsigned > &other_processor_2, Vector< unsigned > &other_shared_boundaries, Vector< unsigned > &other_indexes, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function that assigns/updates the references to the node so that it can be found with any othe...
Definition: triangle_mesh.template.cc:20082
oomph::TriangleMeshParameters::disable_automatic_creation_of_vertices_on_boundaries
void disable_automatic_creation_of_vertices_on_boundaries()
Definition: triangle_mesh.template.h:294
oomph::RefineableTriangleMesh::unrefine_shared_boundary_constrained_by_target_area
bool unrefine_shared_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40663
oomph::TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values
void identify_boundary_segments_and_assign_initial_zeta_values(const unsigned &b, Vector< FiniteElement * > &input_face_ele_pt, const bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Identify the segments from the old mesh (original mesh) in the new mesh (this) and assign initial and...
t
t_0 \f$ and \f$ t=t_0+\Delta t \f$. At \f$ t=t_0+2 \Delta t \f$, the automatic mesh adaptation splits one of the fluid elements, creating the five new \c Nodes, shown in red(for simplicity we only show the fluid elements' vertex nodes). Their position is determined by the father element 's \c MacroElement mapping, using the current position of the \c MeshAsGeomObject, obtained from the interpolation between the nodal positions of its \c SolidNodes(shown as green circles). @I w 0.75\textwidth history_values "Sketch illustrating the assignment of positional history values for newly-created nodes in FSI problems. The positional history values of the newly-created Nodes (shown in red) are given by the positions they would have had if they had already existed at previous timesteps. " So far, so good! A subtle problem arises when we try to assign the positional history values for the newly-created \c Nodes. The evaluation of the \c MacroElement mapping at the previous timesteps(required to determine the positions the newly-created \c Nodes would have had, if they had already existed at previous timesteps) requires access to the previous wall shapes. In< A HREF="../../../navier_stokes/collapsible_channel/html/index.html"> the non-FSI problem discussed earlier</A >, the wall shape was given analytically and could therefore be evaluated at arbitrary times. In the FSI problem considered here, the previous wall shape is not available as the previous positions of the \c SolidNodes are not required(and are therefore not stored) for the solution of the(steady!) wall equations.< HR > \subsection soln The solution:The Steady< NSTEPS > timestepper The solution to the problem is simple:Recall that the final entry in the argument list of \c oomph-lib 's mesh constructors specifies the \c TimeStepper to be used for the evaluation of any time-derivatives. The \c TimeStepper 's member function \c TimeStepper::ntstorage() specifies the total number of values(the current value plus the number of history values) required to evaluate the time-derivatives t
Definition: fsi_collapsible_channel_adapt.txt:100
oomph::RefineableTriangleMesh::add_halo_element_helper
void add_halo_element_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18959
TimeStepper
it is used by the c we always provide a default argument for the pointer to the c TimeStepper a pointer to static a instantiation of c oomph lib s dummy c TimeStepper
Definition: fsi_collapsible_channel_adapt.txt:106
oomph::RefineableTriangleMesh::add_haloed_node_helper
void add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:18696
oomph::RefineableTriangleMesh::add_element_load_balance_helper
void add_element_load_balance_helper(const unsigned &iproc, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, FiniteElement *ele_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27312
oomph::TriangleMeshParameters::set_communicator_pt
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
Definition: triangle_mesh.template.h:260
oomph::TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary
void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(const unsigned &b)
Re-scale the re-assigned zeta values for the boundary nodes, apply only for internal boundaries.
Definition: triangle_mesh.template.cc:6442
oomph::RefineableTriangleMesh::update_polygon_after_restart
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
Definition: triangle_mesh.template.cc:40977
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme_helper
void reset_halo_haloed_scheme_helper(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Node * > > &iproc_currently_created_nodes_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
In charge of creating additional halo(ed) elements on those processors that have no shared boundaries...
Definition: triangle_mesh.template.cc:17459
oomph::RefineableTriangleMesh::update_open_curve_using_face_mesh
bool update_open_curve_using_face_mesh(TriangleMeshOpenCurve *open_polyline_pt, const bool &check_only=false)
Helper function that updates the input open curve by using end-points of elements from FaceMesh(es) t...
Definition: triangle_mesh.template.cc:34362
oomph::RefineableTriangleMesh::create_temporary_boundary_connections
void create_temporary_boundary_connections(Vector< TriangleMeshPolygon * > &tmp_outer_polygons_pt, Vector< TriangleMeshOpenCurve * > &tmp_open_curves_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the temporary r...
Definition: triangle_mesh.template.cc:32757
oomph::RefineableTriangleMesh::refine_shared_boundary_constrained_by_target_area
bool refine_shared_boundary_constrained_by_target_area(Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40873
oomph::TriangleMesh::boundary_segment_node_pt
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
Definition: triangle_mesh.template.h:904
oomph::RefineableTriangleMesh::send_and_receive_elements_nodes_info
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
Definition: triangle_mesh.template.cc:18749
oomph::RefineableTriangleMesh::get_boundary_segment_nodes_helper
void get_boundary_segment_nodes_helper(const unsigned &b, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the boundary (b), these are stored in the segment they belong (also used by the load...
Definition: triangle_mesh.template.cc:28820
oomph::TriangleMesh::get_element_edges_on_boundary
void get_element_edges_on_boundary(std::map< std::pair< Node *, Node * >, unsigned > &element_edges_on_boundary)
Get the element edges (pair of nodes, edges) that lie on a boundary (used to mark shared boundaries t...
Definition: triangle_mesh.template.cc:11570
oomph::TriangleMesh::Point::x
coord_t x
Definition: triangle_mesh.template.h:2097
oomph::RefineableTriangleMesh::adapt
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
Definition: triangle_mesh.template.cc:29344
oomph::TriangleMesh::reset_boundary_element_info
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned > > &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Reset the boundary elements info. after load balance have taken place.
Definition: triangle_mesh.template.cc:14687
oomph::TriangleMesh::create_polylines_from_halo_elements_helper
void create_polylines_from_halo_elements_helper(const Vector< unsigned > &element_domain, std::map< GeneralisedElement *, unsigned > &element_to_global_index, std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< Vector< GeneralisedElement * > > > &input_halo_elements, std::map< std::pair< Node *, Node * >, unsigned > &elements_edges_on_boundary, Vector< Vector< Vector< TriangleMeshPolyLine * > > > &output_polylines_pt)
Creates polylines from the intersection of halo elements on all processors. The new polylines define ...
Definition: triangle_mesh.template.cc:11636
oomph::TriangleMesh::Point::y
coord_t y
Definition: triangle_mesh.template.h:2097
oomph::RefineableTriangleMesh::apply_max_length_constraint
bool apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &max_length_constraint)
Definition: triangle_mesh.template.cc:35279
oomph::RefineableTriangleMesh::add_received_node_load_balance_helper
void add_received_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add a new node from load balance.
Definition: triangle_mesh.template.cc:27577
oomph::TriangleMesh::output_boundary_coordinates
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
Definition: triangle_mesh.template.cc:7902
oomph::RefineableTriangleMesh::create_sorted_face_mesh_representation
void create_sorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt, std::map< FiniteElement *, bool > &is_inverted, bool &inverted_face_mesh)
Helper function Creates a sorted face mesh representation of the specified PolyLine It means that the...
Definition: triangle_mesh.template.cc:35434
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition: triangle_mesh.template.h:2154
oomph::RefineableTriangleMesh::resume_boundary_connections
void resume_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Resume the boundary connections that may have been suspended because the destination boundary is no p...
Definition: triangle_mesh.template.cc:33774
oomph::RefineableTriangleMesh::min_element_size
double & min_element_size()
Min element size allowed during adaptation.
Definition: triangle_mesh.template.h:2374
oomph::TriangleMesh::break_loops_on_shared_polyline_load_balance_helper
void break_loops_on_shared_polyline_load_balance_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< FiniteElement * > &input_boundary_face_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< FiniteElement * > > &output_boundary_face_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:14019
oomph::RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper
void get_shared_boundary_segment_nodes_helper(const unsigned &shd_bnd_id, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the shared boundary (b), these are stored in the segment they belong.
Definition: triangle_mesh.template.cc:25773
AlgebraicMesh
this is used if there is only a single node update as in the c AlgebraicCollapsibleChannelMesh n n A vector such as the intrinsic coordinates of reference points on the c GeomObjects n n By we assume that a newly created c AlgebraicNode is updated by the same node update function as the c AlgebraicNodes in its father element Therefore we pass the pointer to the c AlgebraicMesh
Definition: fsi_collapsible_channel_adapt.txt:199
oomph::TriangleMeshParameters::regions_coordinates
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Definition: triangle_mesh.template.h:230
oomph::RefineableTriangleMesh::construct_new_node_load_balance_helper
void construct_new_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new node (on an element) with the information sent from the load b...
Definition: triangle_mesh.template.cc:27648
oomph::TriangleMesh::dump_distributed_info_for_restart
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7319
oomph::TriangleMeshParameters
Helper object for dealing with the parameters used for the TriangleMesh objects.
Definition: triangle_mesh.template.h:96
oomph::RefineableTriangleMesh::update_polygon_using_face_mesh
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon's PSLG by using the end-points of elements from FaceMe...
Definition: triangle_mesh.template.cc:33876
oomph::RefineableTriangleMesh::add_halo_node_helper
void add_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add halo node.
Definition: triangle_mesh.template.cc:19128
oomph::TriangleMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Definition: triangle_mesh.template.cc:45
oomph::TriangleMesh::shared_boundary_overlaps_internal_boundary
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
Definition: triangle_mesh.template.h:1661
oomph::TriangleMesh::sort_polylines_helper
void sort_polylines_helper(Vector< TriangleMeshPolyLine * > &unsorted_polylines_pt, Vector< Vector< TriangleMeshPolyLine * > > &sorted_polylines_pt)
Sorts the polylines so they be continuous and then we can create a closed or open curve from them.
Definition: triangle_mesh.template.cc:11213
oomph::RefineableSolidTriangleMesh
Unstructured refineable Triangle Mesh upgraded to solid mesh.
Definition: triangle_mesh.template.h:3820
oomph::RefineableTriangleMesh::create_halo_element
void create_halo_element(unsigned &iproc, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18867
oomph::TriangleMesh::oomph_vertex_nodes_id
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
Definition: triangle_mesh.template.h:1118
is
respectively The red arrow identifies the reference point for the newly created node VI whose reference coordinate f IV and i e the nodes in its father element I w textwidth update_single Illustration of the default update procedure for the node update IV and V in its father element the default assignment is not appropriate for nodes that are updated by and the values of the coordinate at which the reference points are located This is illustrated in the sketch below in which the sub c parametrised by their coordinates f f are shown in magenta Note that the reference points for nodes II and IV are located in one sub c those for nodes III and V are located in another I w textwidth update_compound Illustration of the revised update procedure for the node update f at which the reference point with Lagrangian coordinate f it should be implemented in the function c described is appropriate If it is
Definition: fsi_collapsible_channel_adapt.txt:284
GeomObject
this is used if there is only a single node update as in the c AlgebraicCollapsibleChannelMesh n n A vector such as the intrinsic coordinates of reference points on the c GeomObjects n n By we assume that a newly created c AlgebraicNode is updated by the same node update function as the c AlgebraicNodes in its father element Therefore we pass the pointer to the c the node update function and the vector of pointers to c GeomObjects to the newly created c and interpolate the reference values between those stored at the c AlgebraicNodes in the father elements In most cases this provides a sensible default For it is hard to imagine a situation in which it would be sensible to update the position of newly created c AlgebraicNodes by a procedure that differs from that used for the surrounding c AlgebraicNodes that already existed in the father element since the reference values vary from node to in the c AlgebraicCollapsibleChannelMesh one of the reference values is the f x_1 f coordinate of the reference point on the fixed lower wall For the c AlgebraicNodes that already existed in the coarse base this value is given by the the c AlgebraicNodes f x_1 f coordinate in the undeformed mesh Interpolation of this value for the newly created c AlgebraicNodes results in an axially uniform subdivision of the refined elements The same procedure may be used to assign the reference value that represents the intrinsic coordinate of the reference point on the upper wall at least as long as the upper wall is only ever addressed as a compound c GeomObject
Definition: fsi_collapsible_channel_adapt.txt:226
oomph
Definition: annular_domain.h:34
oomph::RefineableTriangleMesh::compute_shared_node_degree_helper
void compute_shared_node_degree_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, std::map< Node *, unsigned > &global_node_degree)
Computes the degree of the nodes on the shared boundaries, the degree of the node is computed from th...
Definition: triangle_mesh.template.cc:24589
oomph::RefineableTriangleMesh::get_required_nodal_information_helper
void get_required_nodal_information_helper(unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from a haloed node so that a fully-functional h...
Definition: triangle_mesh.template.cc:18117
boundaries
mainpage Flow in a collapsible channel revisited enabling adaptivity in FSI problems In this document we re visit the collapsible channel problem yet again this time to demonstrate the use of spatial adaptivity in fluid structure interaction problems In such two additional issues have to be and then explain how these problems are addressed< HR >< HR > section history The assignment of positional history values for newly created nodes subsection what What is the problem We first discussed the use of spatial adaptivity for time dependent problems in the context of< A HREF="../../../unsteady_heat/two_d_unsteady_heat_adapt/html/index.html#spatial_adapt"> the unsteady heat equation</A > We showed that whenever a new node is c oomph lib s mesh adaptation procedures automatically assign the nodal values and history an initial assignment for the newly created c Node s current and previous in which case the newly created c Node s current position is determined by the father element s c MacroElement representation This ensures that the mesh refinement process respects curvilinear domain boundaries
Definition: fsi_collapsible_channel_adapt.txt:42
oomph::RefineableTriangleMesh::get_face_mesh_representation
void get_face_mesh_representation(TriangleMeshPolygon *polygon_pt, Vector< Mesh * > &face_mesh_pt)
Helper function to construct face mesh representation of all polylines, possibly with segments re-dis...
Definition: triangle_mesh.template.cc:35631
oomph::TriangleMeshParameters::element_area
double element_area() const
Helper function for getting the element area.
Definition: triangle_mesh.template.h:176
oomph::TriangleMesh::build_triangulateio
void build_triangulateio(const std::string &poly_file_name, TriangulateIO &triangulate_io, bool &use_attributes)
Helper function to create TriangulateIO object (return in triangulate_io) from the ....
Definition: triangle_mesh.template.cc:7079
oomph::TriangleMesh::compute_holes_left_by_halo_elements_helper
void compute_holes_left_by_halo_elements_helper(Vector< Vector< double > > &output_holes_coordinates)
Compute the holes left by the halo elements, those adjacent to the shared boundaries.
Definition: triangle_mesh.template.cc:10686
oomph::classcomp::operator()
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const
Definition: triangle_mesh.template.cc:15037
oomph::TriangleMesh::synchronize_boundary_coordinates
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
Definition: triangle_mesh.template.cc:5580
oomph::TriangleMesh::set_mesh_level_time_stepper
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
Definition: triangle_mesh.template.h:845
oomph::RefineableTriangleMesh::create_adjacency_matrix_new_shared_edges_helper
void create_adjacency_matrix_new_shared_edges_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, Vector< Vector< Node * > > &tmp_sorted_shared_node_pt, std::map< Node *, Vector< Vector< unsigned > > > &node_alias, Vector< Vector< Vector< unsigned > > > &adjacency_matrix)
Sort the nodes on the new shared boundaries (after load balancing), computes the alias of the nodes a...
Definition: triangle_mesh.template.cc:25587
oomph::TriangleMeshParameters::enable_use_attributes
void enable_use_attributes()
Helper function for enabling the use of attributes.
Definition: triangle_mesh.template.h:244
oomph::RefineableTriangleMesh::refine_triangulateio
void refine_triangulateio(TriangulateIO &triangulate_io, const Vector< double > &target_area, TriangulateIO &triangle_refine)
Build a new TriangulateIO object from previous TriangulateIO based on target area for each element.
Definition: triangle_mesh.template.cc:14882
oomph::TriangleMesh::create_shared_polyline
void create_shared_polyline(const unsigned &my_rank, const unsigned &shd_bnd_id, const unsigned &iproc, const unsigned &jproc, std::list< Node * > &sorted_nodes, const int &root_edge_bnd_id, Vector< FiniteElement * > &bulk_bnd_ele_pt, Vector< int > &face_index_ele, Vector< Vector< TriangleMeshPolyLine * > > &unsorted_polylines_pt, const int &connect_to_the_left_flag, const int &connect_to_the_right_flag)
Create the shared polyline and fill the data structured that keep all the information associated with...
Definition: triangle_mesh.template.cc:14444
oomph::RefineableTriangleMesh::compute_global_node_names_and_shared_nodes
void compute_global_node_names_and_shared_nodes(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Compute the names of the nodes on shared boundaries in this (my_rank) processor with other processors...
Definition: triangle_mesh.template.cc:15894
oomph::RefineableTriangleMesh::update_shared_curve_after_restart
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine * > &vector_polyline_pt)
Updates the shared polylines representation after restart.
Definition: triangle_mesh.template.cc:42676
oomph::TriangleMesh::create_shared_polylines_connections
void create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections....
Definition: triangle_mesh.template.cc:9384
oomph::TriangleMesh::shared_boundaries_ids
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
Definition: triangle_mesh.template.h:1388
oomph::RefineableTriangleMesh::synchronize_shared_boundary_connections
const void synchronize_shared_boundary_connections()
Synchronise the vertices that are marked for non deletion.
Definition: triangle_mesh.template.cc:32408
oomph::RefineableTriangleMesh::send_boundary_node_info_of_shared_nodes
void send_boundary_node_info_of_shared_nodes(Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Get the original boundaries to which is associated each shared node, and send the info....
Definition: triangle_mesh.template.cc:16894
oomph::RefineableTriangleMesh::create_unsorted_face_mesh_representation
void create_unsorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt)
Helper function Creates an unsorted face mesh representation from the specified boundary id....
Definition: triangle_mesh.template.cc:35397
oomph::RefineableTriangleMesh::refine_boundary_constrained_by_target_area
bool refine_boundary_constrained_by_target_area(MeshAsGeomObject *mesh_geom_obj_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40519
oomph::RefineableTriangleMesh::add_non_delete_vertices_from_boundary_helper
void add_non_delete_vertices_from_boundary_helper(Vector< Vector< Node * > > src_bound_segment_node_pt, Vector< Vector< Node * > > dst_bound_segment_node_pt, const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
Adds the vertices from the sources boundary that are repeated in the destination boundary to the list...
Definition: triangle_mesh.template.cc:32321
oomph::Bottom_left_sorter
struct oomph::classcomp Bottom_left_sorter
oomph::RefineableTriangleMesh::get_shared_boundary_elements_and_face_indexes
void get_shared_boundary_elements_and_face_indexes(const Vector< FiniteElement * > &first_element_pt, const Vector< FiniteElement * > &second_element_pt, Vector< FiniteElement * > &first_shared_boundary_element_pt, Vector< unsigned > &first_shared_boundary_element_face_index, Vector< FiniteElement * > &second_shared_boundary_element_pt, Vector< unsigned > &second_shared_boundary_element_face_index)
Use the first and second group of elements to find the intersection between them to get the shared bo...
Definition: triangle_mesh.template.cc:22307
oomph::RefineableTriangleMesh::add_node_load_balance_helper
void add_node_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_halo_ele_pt, Vector< Node * > &new_nodes_on_domain, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:26471
oomph::RefineableTriangleMesh::construct_new_halo_node_helper
void construct_new_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new halo node (on an element) with the information sent from the h...
Definition: triangle_mesh.template.cc:19183
oomph::TriangleMesh::create_shared_boundaries
void create_shared_boundaries(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, const Vector< FiniteElement * > &backed_up_f_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status)
Creates the shared boundaries.
Definition: triangle_mesh.template.cc:11406
oomph::RefineableTriangleMesh::create_element_load_balance_helper
void create_element_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< FiniteElement * > &new_elements_on_domain, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27227
oomph::RefineableTriangleMesh::unrefine_boundary
bool unrefine_boundary(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, const bool &check_only=false)
Helper function that performs the unrefinement process.
Definition: triangle_mesh.template.cc:34844
oomph::TriangleMesh
Definition: triangle_mesh.template.h:365
oomph::classcomp
Definition: triangle_mesh.template.cc:15029
oomph::RefineableTriangleMesh::restore_boundary_connections
void restore_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the boundaries ...
Definition: triangle_mesh.template.cc:32884
oomph::TriangleMesh::read_distributed_info_for_restart
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7566
oomph::TriangleMesh::check_connections_of_polyline_nodes
const int check_connections_of_polyline_nodes(std::set< FiniteElement * > &element_in_processor_pt, const int &root_edge_bnd_id, std::map< std::pair< Node *, Node * >, bool > &overlapped_face, std::map< unsigned, std::map< Node *, bool > > &node_on_bnd_not_overlapped_by_shd_bnd, std::list< Node * > &current_polyline_nodes, std::map< unsigned, std::list< Node * > > &shared_bnd_id_to_sorted_list_node_pt, const unsigned &node_degree, Node *&new_node_pt, const bool called_from_load_balance=false)
Check for any possible connections that the array of sorted nodes have with any previous boundaries o...
Definition: triangle_mesh.template.cc:8945
oomph::TriangleMesh::create_distributed_domain_representation
void create_distributed_domain_representation(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Creates the distributed domain representation. Joins the original boundaires, shared boundaries and c...
Definition: triangle_mesh.template.cc:8017
oomph::RefineableTriangleMesh::update_polygon_using_elements_area
bool update_polygon_using_elements_area(TriangleMeshPolygon *&polygon_pt, const Vector< double > &target_area)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:37421
oomph::RefineableTriangleMesh::get_connected_vertex_number_on_dst_boundary
bool get_connected_vertex_number_on_dst_boundary(Vector< double > &vertex_coordinates, const unsigned &dst_b_id, unsigned &vertex_number)
Computes the associated vertex number on the destination boundary.
Definition: triangle_mesh.template.cc:33820
oomph::RefineableTriangleMesh::add_vertices_for_non_deletion
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods....
Definition: triangle_mesh.template.cc:31598
oomph::TriangleMesh::Point
Definition: triangle_mesh.template.h:2096
s
respectively The red arrow identifies the reference point for the newly created node VI whose reference coordinate f IV and i e the nodes in its father element I w textwidth update_single Illustration of the default update procedure for the node update IV and V in its father element the default assignment is not appropriate for nodes that are updated by and the values of the coordinate at which the reference points are located This is illustrated in the sketch below in which the sub c parametrised by their coordinates f s
Definition: fsi_collapsible_channel_adapt.txt:254
oomph::RefineableTriangleMesh::unrefine_boundary_constrained_by_target_area
bool unrefine_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40264
oomph::TriangleMeshParameters::extra_holes_coordinates
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
Definition: triangle_mesh.template.h:182
oomph::TriangleMesh::create_tmp_open_curves_helper
void create_tmp_open_curves_helper(Vector< Vector< TriangleMeshPolyLine * > > &sorted_open_curves_pt, Vector< TriangleMeshPolyLine * > &unsorted_shared_to_internal_poly_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Take the polylines from the original open curves and created new temporaly representations of open cu...
Definition: triangle_mesh.template.cc:8904